URL: https://testingbot.com/ # Cross Browser & Mobile App Testing Platform With over 9 years of experience, our App and Browser Testing service is powerful, easy to use and provides you with a big number of features tailored to help you improve your product. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) 1+bn Tests Executed 180k Active Users 5,500+ Browsers & Devices Trusted by some of the world's most innovative companies ## Test your websites and mobile apps ### Web Testing Test on 5200+ real browsers across Windows, macOS and Linux. [ #### Live / Manual Interactive browser testing ](https://testingbot.com/features/manual-browser-testing)[ #### Automated Selenium, Playwright, Puppeteer & Cypress ](https://testingbot.com/features)[ #### AI Testing No-code test creation ](https://testingbot.com/features/ai-testing)[ #### Visual Testing Screenshot comparison of websites ](https://testingbot.com/features/screenshot-testing) ### Mobile App Testing Test on real physical iOS and Android devices. [ #### Live / Manual Interactive device testing ](https://testingbot.com/features/manual-mobile-testing)[ #### Automated Appium, Espresso, XCUITest & Maestro ](https://testingbot.com/mobile/realdevicetesting)[ #### AI Testing Natural language tests for Apps ](https://testingbot.com/features/ai-testing)[ #### Visual Testing App screenshot comparison ](https://testingbot.com/features/screenshot-testing) ![App screenshot comparison](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Cross-Browser Testing Made Simple Get one-click access to real browsers running on macOS, Windows and Linux platforms. Switch platforms, locations and screen resolutions instantly. Test across all versions of Internet Explorer (IE8 to IE11), Edge, Chrome, Safari, Firefox and Opera. ![Chrome](https://testingbot.com/assets/home/chrome-97eb1fabe899086fad592ef3ed29d82d0a206a2002d5c3be62079a3163391e1d.svg)Chrome ![Safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg)Safari ![Firefox](https://testingbot.com/assets/home/firefox-a8ee4666d002663e9868f9b15eb50f681cc03839ae1ead6432353c617496b95d.svg)Firefox ![Edge](https://testingbot.com/assets/home/edge-8204f73ccd649193b2a4d066840b4431b982015625e0c42a95bf91b5eec127b2.svg)Edge [Start Testing](https://testingbot.com/features/manual-browser-testing) ## Why teams choose TestingBot ### Improve test coverage Cross-browser, real device and visual testing on 5500+ browser and device combinations. ### Boost productivity with AI AI-powered test creation and execution. Write tests in natural language, let AI do the rest. ### Accelerate testing cycles Run tests in parallel across multiple browsers and devices. Ship faster with confidence. ## Works with your favorite testing frameworks Native support for all major web and mobile testing frameworks. Get started in minutes. ### Web Testing [![Selenium](https://testingbot.com/assets/integrations/selenium-1403d7bf83f64f56f05cea3fe50ae45bc3025d5a2433b7b05d2b199fec753cf6.svg)Selenium](https://testingbot.com/support/web-automate/selenium)[![Playwright](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)Playwright](https://testingbot.com/support/web-automate/playwright)[![Cypress](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)Cypress](https://testingbot.com/support/web-automate/cypress)[![Puppeteer](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer)[WebdriverIO](https://testingbot.com/support/web-automate/selenium/webdriverio)[![Robot Framework logo](https://testingbot.com/assets/wizard/robotframework-08821f4942343bcb1f828470b5cbff3163369c14884b7ca285be190017ee7a94.png)RobotFramework](https://testingbot.com/support/web-automate/selenium/nightwatch) ### Mobile Testing [![Appium](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium)[![Espresso](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)Espresso](https://testingbot.com/support/app-automate/espresso)[![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)XCUITest](https://testingbot.com/support/app-automate/xcuitest)[![Maestro](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)Maestro](https://testingbot.com/support/app-automate/maestro)[Flutter](https://testingbot.com/support/app-automate/appium/flutter)[React Native](https://testingbot.com/support/app-automate/appium) ### Languages & SDKs [Java](https://testingbot.com/support/web-automate/selenium/java)[Python](https://testingbot.com/support/web-automate/selenium/python)[NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs)[C# / .NET](https://testingbot.com/support/web-automate/selenium/csharp)[Ruby](https://testingbot.com/support/web-automate/selenium/ruby)[phpPHP](https://testingbot.com/support/web-automate/selenium/php) [View all documentation](https://testingbot.com/support) Real Device Cloud ## Test on real iOS & Android devices Access hundreds of real physical devices for manual and automated testing. iPhones, iPads, Samsung Galaxy, Pixel, Smart TVs and more. ![Appium](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg) Appium ![Espresso](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg) Espresso ![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg) XCUITest ![Maestro](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg) Maestro [Explore device cloud](https://testingbot.com/mobile/realdevicetesting) ![Real device testing](https://testingbot.com/assets/hero/app-testing-eb9e2816aa7dce01b215db1df0a54c361c2ff9b8c30850a5dd00f088c9255cb3.webp) AI-Powered Testing ## AI Test Agent Create and run tests without writing code. Simply describe what you want to test in plain language. TestingBot AI understands your application and generates reliable test steps automatically. [Try AI Testing](https://testingbot.com/features/ai-testing) ![AI Testing Interface](https://testingbot.com/assets/home/ai-chat-24cc1ab8234690bad4a866888a2bd8e11f1301b7e21ad86be5d4d61be838707a.webp) ![Accessibility Testing Dashboard](https://testingbot.com/assets/features/accessibility/accessibility_ui-b64827a2253e7d403626e287a9da43bbf597d15b8e61fce56a53d8f3ffb9db1a.jpg) Accessibility Testing ## WCAG Compliance Testing Identify and fix accessibility issues across your websites. Ensure WCAG compliance and deliver an inclusive experience for all users. Meet legal requirements like the European Accessibility Act (EAA), reach a broader audience and improve SEO with accessibility best practices. WCAG 2.1 Compliance Scheduled Testing Detailed Reports Severity Classification [Explore Accessibility Testing](https://testingbot.com/features/accessibility-testing) ## Trusted by teams worldwide Join thousands of companies shipping better software with TestingBot 0+ Tests Executed 0+ Active Users 0+ Browsers & Devices 0 Countries GDPR Compliant SAML SSO Single Sign-On Star Level 1 Certified 99.99% Uptime SLA ## Seamlessly integrate into your workflow Connect TestingBot with your CI/CD pipeline, issue trackers and communication tools. [![Jenkins](https://testingbot.com/assets/home/integrations/jenkins-99fe0a162ffc131f4b0dfc0929f8919e6c671555d418ba1ea8d4166e0b5d314a.webp)Jenkins](https://testingbot.com/support/integrations/jenkins)[![GitHub Actions](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp)GitHub](https://testingbot.com/support/integrations/github-actions)[![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp)GitLab](https://testingbot.com/support/integrations/gitlab)[![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp)CircleCI](https://testingbot.com/support/integrations/circleci)[![Travis CI](https://testingbot.com/assets/integrations/travis-f3a8872deab0dd6f4c13686fd8255cb07c426309090e335a9198312b49c43232.webp)Travis CI](https://testingbot.com/support/integrations/travis-ci)[![Slack](https://testingbot.com/assets/home/integrations/slack-bb80ee3eab2780485942bb08f04c207f99b471ef243aa5d98342b63d725cc258.svg)Slack](https://testingbot.com/support/integrations/slack)[![Jira](https://testingbot.com/assets/home/integrations/jira-883ba56e56e7c50d4c67c5500062c4161a6f21d052f7781b73fb2f32f936da17.webp)Jira](https://testingbot.com/support/integrations/jira)[Azure](https://testingbot.com/support/integrations/azure-devops)[![Bitbucket](https://testingbot.com/assets/integrations/bitbucket-02aabcd549221726e052f2ee19c8959fbb218160ad7f7c31f6e6b96e7824a42c.webp)Bitbucket](https://testingbot.com/support/integrations/bitbucket)[![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg)TeamCity](https://testingbot.com/support/integrations/teamcity)[![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg)Bamboo](https://testingbot.com/support/integrations/bamboo)[![App Center](https://testingbot.com/assets/integrations/app-center-icon-2c5c0d6c296fd04d1d3d0109db02dde20bb93a5ee7a9616e7805f27d6ec6503a.svg)App Center](https://testingbot.com/support/integrations/app-center) [View all integrations](https://testingbot.com/integrations) No credit card required ## Ready to get started? Join thousands of teams shipping better software with TestingBot [Start Free Trial](https://testingbot.com/users/sign_up)[View pricing](https://testingbot.com/pricing) Free 14-day trial 5-minute setup 24/7 support --- URL: https://testingbot.com/features # Cross-Browser Testing Test your website and app on **5200+ real browsers and devices**. Speed up your UI tests with parallel execution on a real browser and device cloud. Catch bugs earlier, release faster and boost developer productivity. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Automated Testing](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) ## Trusted by some of the world's most innovative companies ## All-in-one cross browser testing platform The TestingBot cloud brings you the power to test your website and mobile app on [+5200 browsers & devices](https://testingbot.com/support/web-automate/browsers). Test across all major browsers and operating systems in our cloud — including Internet Explorer, Edge, Firefox, Chrome, Safari (mobile and desktop) and beyond. Let us handle your testing infrastructure while you focus on development. Run tests effortlessly on our maintained cloud of desktop and mobile platforms. [Get started free](https://testingbot.com/users/sign_up) ![Automated Testing Platform](https://testingbot.com/assets/features/coverage-d16d677b6a3ac8fac706949abfa45577d35762f298030c3f59a561e7b5fbd8b4.jpg) ## 5200+ real desktop & mobile browser combinations Test on the widest range of desktop and mobile devices in our real device cloud. We handle setup, procurement and maintenance — so you can focus entirely on testing. ### Windows, macOS & Linux One-click access to every macOS, Linux and Windows version. From Yosemite to macOS Sequoia, and Windows XP to Windows 11. We've got you covered. ### Every browser, all versions Edge, Safari, Firefox, Chrome, Opera and IE - constantly updated & instantly available. ### Security Single-Use VMs and pristine real devices, reset after each use. ### Real Android & iOS devices Test across real iPhone, iPads, Google, OnePlus, Xiaomi and Samsung phones & tabs. ### No setup & maintenance Instantly access 5200+ devices and browsers. Experience zero setup or maintenance hassles, and focus only on testing. ### Performance Our infrastructure is built for performance to eliminate test flakiness and latency. ## Test Automation Frameworks TestingBot supports these popular Test Automation Frameworks: [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/features/automation/selenium) ### [Selenium](https://testingbot.com/features/automation/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/features/automation/appium) ### [Appium](https://testingbot.com/features/automation/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)](https://testingbot.com/features/automation/cypress) ### [Cypress](https://testingbot.com/features/automation/cypress) Javascript based E2E testing on Chrome and Firefox. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/features/automation/puppeteer) ### [Puppeteer](https://testingbot.com/features/automation/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/features/automation/playwright) ### [Playwright](https://testingbot.com/features/automation/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. [![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)](https://testingbot.com/features/automation/espresso) ### [Espresso](https://testingbot.com/features/automation/espresso) Android Automation Framework, runs on physical devices and emulators. [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)](https://testingbot.com/features/automation/xcuitest) ### [XCUITest](https://testingbot.com/features/automation/xcuitest) iOS Automation Framework, runs on physical devices and simulators. [![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)](https://testingbot.com/features/automation/maestro) ### [Maestro](https://testingbot.com/features/automation/maestro) Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. ## Take control of a device Interact with the remote mobile device, just as you would with a device in hand. Tap, scroll, zoom, swipe and more. ![Parallel Testing](https://testingbot.com/assets/features/control-device-114c527535e472dd402c03580fdb23b36ab5716387bc5448c5d6d4262219b655.jpg) ## Test Frameworks TestingBot integrates with various test frameworks and services. Easily convert your existing Selenium tests and connect with your favorite CI/CD. ### [C#](https://testingbot.com/support/web-automate/selenium/csharp) ### [NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs) ### [Java](https://testingbot.com/support/web-automate/selenium/java) ### [PHP](https://testingbot.com/support/web-automate/selenium/php) ### [Python](https://testingbot.com/support/web-automate/selenium/python) ### [Ruby](https://testingbot.com/support/web-automate/selenium/ruby) ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Test on real mobile & desktop devices Get one-click access to real browsers running on macOS, Windows and Linux platforms. Cross-browser testing made simple: switch platforms, locations and screen resolutions instantly. Test across all versions of Internet Explorer (IE8 to IE11), Edge, Chrome, Safari, Firefox and Opera. [Get started free](https://testingbot.com/users/sign_up) ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile/realdevicetesting # Automated Mobile App Testing TestingBot offers automated testing on a wide variety of physical devices, including iPhone, iPad, Samsung Galaxy, Pixel, Xiaomi and more. Seamlessly integrate with your favorite mobile testing frameworks like Appium, Espresso, XCUITest and Maestro for comprehensive test coverage. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Automated Mobile App Testing](https://testingbot.com/assets/hero/app-testing-eb9e2816aa7dce01b215db1df0a54c361c2ff9b8c30850a5dd00f088c9255cb3.webp) Trusted by some of the world's most innovative companies ## Reliable Device Farm Get instant access to a fast, reliable device infrastructure. ### 24/7 device availability Physical iOS and Android devices, available at any time of the day. ### Zero setup & Maintenance Focus on testing instead of worrying about setup and maintenance of a mobile device farm. ### Security Devices located in a datacenter in Europe. Each test runs on a secure and pristine device. ### Real Android & iOS devices Test across real iPhone, iPads, Google, OnePlus, Xiaomi and Samsung phones & tabs. ### Variety of devices Test on any device — flagship or budget — with support for the newest and legacy iOS and Android versions. ### Performance Our infrastructure is built for performance to eliminate test flakiness and latency. ## Test Automation Frameworks Works instantly with these app automation frameworks: [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/features/automation/appium) ### [Appium](https://testingbot.com/features/automation/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)](https://testingbot.com/features/automation/espresso) ### [Espresso](https://testingbot.com/features/automation/espresso) Android Automation Framework, runs on physical devices and emulators. [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)](https://testingbot.com/features/automation/xcuitest) ### [XCUITest](https://testingbot.com/features/automation/xcuitest) iOS Automation Framework, runs on physical devices and simulators. [![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)](https://testingbot.com/features/automation/maestro) ### [Maestro](https://testingbot.com/features/automation/maestro) Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. ## Parallel Testing Drastically shorten your total App test duration by running tests simultaneously. TestingBot provides a variety of devices, ready to run your tests in parallel. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ## Video, screenshots & logs Every mobile test comes with access to generated logs, videos and screenshots. [Get started free](https://testingbot.com/users/sign_up) ![Video, screenshots & logs](https://testingbot.com/assets/features/app-automated-report-dcef51604982dffa3ee9f02b87a92cef82132f9e21c5b66683738ab69f634ecf.jpg) ## TestingBot Storage Upload your native mobile app, as an .apk or .ipa, to [TestingBot Storage](https://testingbot.com/support/api#upload) and start testing immediately. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/tb-storage-a1d1845fbed2bac0012e225de7f847431af6ffdb9dd9b6233fd3145ef3681cb9.jpg) ## Test native device features Access and modify device features to test your app in various real-world conditions. ### Network Simulation Test for scenarios like connectivity, fluctuating network & many more. ### Localization testing Test your apps across different timezones, languages and geolocations. ### Dark Mode Test your app's UI with a dark background to ensure a smooth user experience. ### App Orientation Test your app in the landscape or portrait mode. Switch between orientations to test your app's response. ### Audio Record and hear in realtime the audio generated on the device. ### Settings Control various settings on the device, through ADB or other. ## Your very own Mobile Devices Choose your own iOS and Android devices. We will purchase these devices, install and configure them in our secure datacenter. These devices will be only available to you, 24x7. Private devices can be customised to your needs. Have us install specific profiles and apps, or change specific settings of the device. You decide. [Contact us](https://testingbot.com/contact/new) ![Private Device Cloud](https://testingbot.com/assets/enterprise/datacenter-d4fc366e9a4e8a106ec41e6817e21adb2aeb366a397ac258fd29ba9cd4de72c4.jpg) ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Testing Flutter Apps with Appium](https://testingbot.com/assets/resources/articles/13-77f190ec948df41b31594f8fc224348844ebc412f374eb6f18c9d4215b4fa49b.webp)](https://testingbot.com/resources/articles/appium-flutter-app-testing) #### [Testing Flutter Apps with Appium](https://testingbot.com/resources/articles/appium-flutter-app-testing) Learn how to do automated mobile app testing with Flutter and Appium. [Read more](https://testingbot.com/resources/articles/appium-flutter-app-testing) [![How to do localisation testing for mobile apps](https://testingbot.com/assets/resources/articles/12-9db6c7be671827ade1212fa6e476ee36e3365f01569100ee46fe22405c035760.webp)](https://testingbot.com/resources/articles/localized-testing-mobile-app) #### [How to do localisation testing for mobile apps](https://testingbot.com/resources/articles/localized-testing-mobile-app) Find out how to perform localisation testing with mobile apps. Change your language or locale with Appium, XCUITest and Espresso. [Read more](https://testingbot.com/resources/articles/localized-testing-mobile-app) [![Dark Mode Testing with Appium](https://testingbot.com/assets/resources/articles/22-ed15fa0f3fde7566416fff5078b44689dc274439b2fb829f8c68603e909a65d6.webp)](https://testingbot.com/resources/articles/dark-mode-testing) #### [Dark Mode Testing with Appium](https://testingbot.com/resources/articles/dark-mode-testing) Perform dark mode automated testing on iOS and Android with Appium. [Read more](https://testingbot.com/resources/articles/dark-mode-testing) --- URL: https://testingbot.com/pricing # PRICING PLANS Take your testing to the next level with **TestingBot**. ### Live Manual testing of websites and apps $20/month Billed annually Or $30 month-to-month 1 User 2 Users 4 Users 10 Users 25 Users - **Unlimited** Live Testing - **Unlimited** Visual Testing - Real iOS & Android devices - 24x7 Active Support via Email, Chat & Slack [Upgrade Plan](https://testingbot.com/pricing/1) ### Automated Automated web and app testing $50/month Billed annually Or $70 month-to-month 1 Parallel Test - 1,000 minutes 2 Parallel Tests - 2,000 minutes 4 Parallel Tests - 4,000 minutes 8 Parallel Tests - 6,000 minutes 16 Parallel Tests - 10,000 minutes 24 Parallel Tests - 20,000 minutes - **1000** minutes Automated / month - **Unlimited** Live testing - **Unlimited** Visual Testing - Real iOS & Android devices - 24x7 Active Support via Email, Chat & Slack [Upgrade Plan](https://testingbot.com/pricing/6) MOST POPULAR ### Automated Pro Unlimited web and app testing $90/month Billed annually Or $120 month-to-month 1 Parallel Test - Unlimited 2 Parallel Tests - Unlimited 4 Parallel Tests - Unlimited 8 Parallel Tests - Unlimited 16 Parallel Tests - Unlimited 24 Parallel Tests - Unlimited - **Unlimited** Live Testing - **Unlimited** Visual Testing - **Unlimited** Automated - Real iOS & Android devices - 24x7 Active Support via Email, Chat & Slack [Upgrade Plan](https://testingbot.com/pricing/12) ### Enterprise Enterprise-grade testing for large teams For Premium features & Enterprise-grade security 10+ Parallel Tests - **Unlimited** Testing - Single Sign On - Priority Support - [other Enterprise Features](https://testingbot.com/enterprise) [Contact us](https://testingbot.com/contact/new) ### Detailed Plan Comparison Feature List Live$20/month(Billed annually) [Upgrade Plan](https://testingbot.com/pricing/1) Automated$50/month(Billed annually) [Upgrade Plan](https://testingbot.com/pricing/6) Pro$90/month(Billed annually) [Upgrade Plan](https://testingbot.com/pricing/12) EnterpriseFor Premium features & Enterprise-grade security [Contact us](https://testingbot.com/contact/new) Testing Minutes Unlimited Starts at 1000 minutes / month Unlimited Unlimited Users - Unlimited Unlimited Unlimited Desktop Browsers Mobile Devices Visual Testing Automated Testing - AI Testing Run tests without writing any code. The AI Agent will create and run tests for you. - Accessibility Testing - Test Analytics - Single-Use Machines TestingBot provides single-use machines: you always start secure, with a clean machine. REST API Access Customizations - - - High Volume Testing - - - Local testing Test Local Websites High Availability Mode - - - Testing Features Mobile DevTools Access to Native DevTools on real browsers and devices. GPS Geolocation Testing from 100+ countries Geolocation Testing Test your application from over 15 geographic locations around the world. Network Throttling Simulate various network conditions, such as 3G, 4G and offline modes, to test your application's performance under different connectivity scenarios. Integrations Slack JIRA GitHub [CI/CD](https://testingbot.com/support/integrations/ci-cd) Administration 2-Factor Authentication (2FA) SAML 2.0 Single sign-on (SSO) - - Analytics per team & team-member - - - Auto User Provisioning - - - IP Whitelisting (inbound & outbound) - - - Support 24x7 Availability Email Support Priority Support - - - ## All plans include - **Over [5200+ real desktop browsers](https://testingbot.com/support/web-automate/browsers) and [physical mobile devices](https://testingbot.com/support/app-automate/devices)** - **Real Browsers on Windows, macOS and Linux** - **Range of screen resolutions** - **Videos and screenshots of your tests** - **Team management** - **Local testing** - **Android/iOS Native App Testing** - **Tech support and Documentation** - **Unlimited Screenshots & Manual tests** ### All Plans Every plan includes all our OS/browser/device platforms with real-time availability of VMs. Also included is video test playback, unlimited manual tests, unlimited screenshots and debugging tools. TestingBot integrates with any language, framework and CI system. ### Do I need a creditcard to register? No, you do not need a credit card. With our free plan you can try our service for 28 days without paying anything. When you want to upgrade to a paid plan, you can easily upgrade by credit card or wire transfer. Additional payment options are available for EU customers. ### Subscription Our plans come with a subscription which you can cancel at any time. If you decide to upgrade your account, the upgrade will take effect immediately. If you had a previous plan, the remaining prorated amount will be refunded. Downgrades take effect on the next billing cycle. ### What is a Parallel Test? Parallel tests indicate how many tests you can run at the same time. More parallel tests, means a higher decrease in overal test time. Calculate how many parallel tests you need with the [Parallel Test Calculator](https://testingbot.com/support/parallel-calculator). ### Free Open Source Plan We love open source projects! If you have an Open-Source project, please [sign up for our open-source plan](https://testingbot.com/open-source). ### Exceeding quota Once your available testing time for a month has ended you can no longer run any tests during that month. If you wish to continue running tests, please consider upgrading your plan. ### Forms of payment We accept credit card payments and wire transfer ([contact us](https://testingbot.com/contact/new)). ## Need help finding the right solution for your needs? Contact us and we'll help you find the right plan for your needs. [Contact us](https://testingbot.com/contact/new) --- URL: https://testingbot.com/enterprise # Enterprise We help companies ship code with test-confidence. TestingBot offers enterprise-grade security, advanced administrative controls and powerful reporting tools. [Contact Sales](https://testingbot.com/contact/new) ![Enterprise](https://testingbot.com/assets/hero/img-tech-illustration@2x-09902038d331f9f8aa14c183489bb9c9eb15ce8f9cd8026235e52b48909ca890.webp) Trusted by some of the world's most innovative companies ## Enterprise-grade Security and Compliance We adhere to enterprise-grade privacy standards, including GDPR compliance. Learn more on the [Security Overview Page](https://testingbot.com/security) and in the [TestingBot Trust Center](https://trust.testingbot.com). ### Single-Use VMs - TestingBot provides single-use VMs for every test, allowing you to customize the OS before each run. - Each VM is **firewalled** , ensuring only you can access it. ### Network security - Use IP whitelisting or TestingBot tunnel to create a secure connection between your service and TestingBot. ### Data Control - User Management: customize permissions and access, assign roles to users in your organization. - Data Retention: control how long your data is stored. Indicate which generated test assets you want to keep and for how long. ![Parallel Testing](https://testingbot.com/assets/enterprise/sso-139348f54ce00af26f82991b8750ad2d58d1cdb98ec9eb75ec2fd2d88f785e6c.webp) ## Advanced Team Management & Secure Access Controls Manage teams at scale with granular access controls, enforced 2FA, Single Sign-On (SAML), usage tracking and secure Tunnel sharing. ### Enterprise-Grade Access Control - Single Sign-On (SSO): Enhance security and streamline the login experience for your team. Seamlessly integrate with identity providers like Okta, Azure AD, OneLogin and more using pre-built or custom SAML connectors. - Two-Factor Authentication (2FA): Add an extra layer of protection with two-step verification. Ensure secure access, reduce unauthorized logins and support compliance requirements for handling sensitive data. ### Auto-provisioning/de-provisioning - Seamlessly onboard team members and manage user licenses, roles, teams and product access directly through your Identity Provider. ### Centralized User Management - Apply limits to your team members, such as maximum number of parallel tests, or access to specific features. ![Parallel Testing](https://testingbot.com/assets/enterprise/teams-29607dc2a6363c1d8706fa18a02eef3d6861874e87546eebe807a73c7fd224ee.webp) ## Private Device Cloud With Private Device Cloud, we take care of the setup, configuration and maintenance of dedicated devices exclusively for your company. Unlike our Public Device Cloud, these devices are reserved only for your team, ensuring full control and privacy. Select your preferred devices, and we will make them available in our data center for seamless testing. Run both automated and manual tests on your private iOS and Android devices with full control and security. [Learn more](https://testingbot.com/enterprise/private-device-cloud) ![Private Device Cloud](https://testingbot.com/assets/enterprise/private-01e26e5dad16fa4b9b824124cec4112843b10fdf88c7432e8c0c0e873bab5900.webp) ## Experience Best-in-class TestingBot Support Get the support you need, when you need, from the experts you trust, to reach your business goals faster. | Support | Standard | Enterprise | | --- | --- | --- | | Custom Legal Terms | | | | Dedicated Support person & Customer Success Manager | | | | Dedicated Solution Engineer | | | | Phone Support | | 24/7 | | Email Support | 24/5 | 24/7 | | Chat Support | | | ## How does TestingBot for Enterprise Compare? | | Standard Plans | Enterprise Plans | | --- | --- | --- | | Security & Compliance | | IP Whitelisting (inbound & outbound) | – | | | Single-Use VMs + Firewalled | | | | 2FA enforcement | – | | | Administration | | SAML 2.0 Single sign-on (SSO) | – | | | Sub-teams, parallel sessions per team | – | | | Analytics per team & team-member | – | | | Support | | Dedicated Support person & Customer Success Manager | – | | | Custom SLA | – | | | 24/7 priority support via phone and e-mail | – | | | Product | | Customize OS / Pre-installed Software | – | | | Early access to beta features | – | | | Unlimited Users | – | | ### Contact us Learn how your business can take full advantage of TestingBot for Enterprise. [Contact us](https://testingbot.com/contact/new) --- URL: https://testingbot.com/security # We take security seriously TestingBot takes great care of the privacy and security of your data. We take great pride in providing a secure platform service. [Get started free](https://testingbot.com/users/sign_up)[Download our Security Whitepaper](https://testingbot.com/downloads/testingbot_security_whitepaper.pdf) ![Enterprise](https://testingbot.com/assets/hero/img-tech-illustration-2e8380f5c9955178e74d9c8bb7666845ff8b7d21c21e9185a5a05016dbc97158.webp) [![Star Level One certificate](https://testingbot.com/assets/security/star-11edcc06553505b9273f1b262013331690e0898a62e098ea785ef5781f32a53e.png)](https://cloudsecurityalliance.org/star/registry/testingbot/services/testingbot/)[![GDPR ready](https://testingbot.com/assets/security/gdpr-7823fb95f16df44e3d7aa0c6b0541d66fce3db81ce70907bc8fad94d0b0ac1e6.png)](https://testingbot.com/privacy) ## Single-Use VMs For every test you run, we spin up a brand new virtual machine (VM) with the platform/browser/device you want to test on. Every test runs on a pristine, freshly booted machine. Everything your test does on the VM is written to a RAM-disk (memory) through COW (Copy-On-Write). At the end of your test, after we've collected screenshots, logs and video of the test, we instruct our hypervisor to fully erase the RAM-disk and the VM. ![Single-Use VMs](https://testingbot.com/assets/features/security/vm-single-use-73422b5368f650fab42e9347f555e766870574895050250f4acee6b131d34148.webp) ## Firewall Every test runs on its own, firewalled, VM. TestingBot ensures only you can access the VM, all other traffic is blocked by enforcing a firewall for every VM you run. VMs can only access the public internet. Or, in case you're running a TestingBot Tunnel, the content on your computer/network. ![Firewall](https://testingbot.com/assets/features/security/vm-firewall-w-9cdbf732b5b54c483c1fc083aaf962e5e3c49d12159ab2520cebad2121ebf582.webp) ## Test Assets By default, we take screenshots and a video of your test, together with logging of various components (Selenium Logs, Chrome-Driver Logs, Firefox-Driver Logs, Console Logs, ...) These assets are uploaded to our assets servers via SSL. Access to these assets is restricted: we create a signed URL for each asset. Each asset is only accessible via SSL for 30 minutes. You can also disable any logging, screenshot-taking and video-recording. This way we will not record anything that happens during your test. ![Test Assets](https://testingbot.com/assets/features/security/test-assets-024bf2b7f827a381f5994ff2378042134d9646e597f5744c574ef212c0fd9a22.webp) ## Team Policies Add colleagues to your team and enforce user policies as an account owner, such as: - Enforce 2FA (Two-Factor Authentication) during login - Set user-account to read-only - Reset user credentials - Promote a user to Administrator level - Set the maximum number of simultaneous tests As an owner or administrator, you can distribute the number of parallel tests your subscription is allowed to run between members of your team. You can see an overview of any user's activity (test runs, logins, ...) and add/remove users to your team. ![Test Assets](https://testingbot.com/assets/features/security/team-16ae4b94abf72d27b8e97ea1d67dc98b9eafc3e5ea98010739bfd9ce9ceb298d.webp) ### Contact us Learn how your business can take full advantage of TestingBot for Enterprise. [Contact us](https://testingbot.com/contact/new) --- URL: https://testingbot.com/enterprise/private-device-cloud # Private Real Device Cloud Dedicated iOS and Android devices for you and your team. We provision the devices you want, customized to your needs. [Contact Sales](https://testingbot.com/contact/new) ![Enterprise](https://testingbot.com/assets/enterprise/hero-916e6a5a37e37edc64dd8dfabee8d3cdf44ed4e5091dc0017b46dfa3727e1885.webp) Trusted by some of the world's most innovative companies ## Your very own Mobile Devices Choose your own iOS and Android devices. We will purchase these devices, install and configure them in our secure datacenter. These devices will be only available to you, 24x7. Private devices can be customised to your needs. Have us install specific profiles and apps, or change specific settings of the device. You decide. [Contact us](https://testingbot.com/contact/new) ![Private Device Cloud](https://testingbot.com/assets/enterprise/datacenter-d4fc366e9a4e8a106ec41e6817e21adb2aeb366a397ac258fd29ba9cd4de72c4.jpg) ## Test on Real Carrier Networks with SIM or eSIM We can equip your devices with a physical SIM or eSIM, enabling true carrier connectivity. This allows you to test scenarios that are not possible over Wi-Fi, like sending and receiving SMS, making and receiving calls, and verifying mobile data behavior in real-world conditions. ![Private Device Cloud](https://testingbot.com/assets/enterprise/sims-ef855544bead23d65f39cdc10fba272c2a93d82fa0e28026ab6ea10fd91131e6.jpg) ## Private Device Cloud: Devices Dedicated to You With our Private Device Cloud, your devices are reserved exclusively for your use. While TestingBot thoroughly cleans all public devices after each test, the complexity of mobile systems means complete data removal can't always be guaranteed. Private devices ensure full test isolation—only you have access, and there's no waiting for others to finish using the device. ![Private Device Cloud](https://testingbot.com/assets/enterprise/private_devices-62c56d55c281473f0e3fb580ac5c9db976b23d93d8bf7e81a66c924f4f25cf93.jpg) ### Contact us Learn how your business can take full advantage of TestingBot for Enterprise. [Contact us](https://testingbot.com/contact/new) --- URL: https://testingbot.com/partners # Partner with TestingBot Join our partner ecosystem to expand your business opportunities and enhance your product capabilities with TestingBot's next generation testing platform. [Technology Partners](https://testingbot.com/partners/technology-partners)[Reseller Partners](https://testingbot.com/partners/reseller-partners) - 1+bn Tests Executed - 180k Active Users - 5,500+ Browsers & Devices ![Partner with TestingBot](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ## Partner Programs Choose the partnership that best fits your business needs and goals. ### Technology Partners TestingBot platform integrates with tools that developers use daily. Partner with us to enhance your product capabilities, reduce interruptions for developers and expand customer reach. - API integration support - Co-marketing opportunities - Technical support and documentation [Learn More](https://testingbot.com/partners/technology-partners) ### Reseller Partners Expand your business by partnering with TestingBot. Join our Partner Program and earn lucrative commissions, receive dedicated support and gain recognition for your sales success. - Competitive commission rates - Dedicated partner support - Sales and marketing materials [Learn More](https://testingbot.com/partners/reseller-partners) ### Ready to Partner with Us? Join TestingBot's growing partner ecosystem and unlock new opportunities for your business. [See existing integrations](https://testingbot.com/integrations) --- URL: https://testingbot.com/partners/technology-partners # Technology Partners TestingBot platform integrates with tools that developers use daily. Partner with us to enhance your product capabilities, reduce interruptions for developers and expand customer reach. [Apply now](https://testingbot.com#apply)[All Partner Programs](https://testingbot.com/partners) ![Technology Partners](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ## Partner Benefits Join our technology partner program and unlock powerful integrations with TestingBot's comprehensive testing platform. ### API Integration Support Get comprehensive technical documentation, SDKs and dedicated engineering support for seamless integration. ### Co-Marketing Opportunities Joint marketing initiatives, case studies, webinars and placement in our partner directory to expand your reach. ### Technical Documentation Access to comprehensive technical resources, integration guides and best practices documentation. ### Partner Portal Access Dedicated partner portal with resources, training materials and integration tracking tools. ### Priority Support Dedicated technical support channel with priority response times for integration issues. ### Partner Recognition Featured placement in our partner ecosystem, case studies and recognition at industry events. ## Integration Opportunities Partner with TestingBot to create powerful integrations that enhance developer workflows and provide seamless testing experiences. - **Integrate into your product:** Embed our testing capabilities into your app. Offer automated testing to your customers through TestingBot's whitelabel automated testing offerings, or embed realtime live testing in your product. - **Developer Advocate:** Help developers use TestingBot's platform. We supply you with documentation, tools and free extended trial credits. - **Integrate your product with TestingBot:** Create an integration between TestingBot and your product. ![Technology Integration](https://testingbot.com/assets/features/coverage-d16d677b6a3ac8fac706949abfa45577d35762f298030c3f59a561e7b5fbd8b4.jpg) ## Apply to Become a Technology Partner Ready to integrate with TestingBot? Fill out the form below and our partnership team will be in touch. Company Name \* Email Address \* Tell us about your integration \* Submit Application --- URL: https://testingbot.com/partners/reseller-partners # Reseller Partners Expand your business by partnering with TestingBot. Resellers in the Partner Program enjoy lucrative commissions, dedicated support and recognition for their sales excellence. [Apply now](https://testingbot.com#apply)[All Partner Programs](https://testingbot.com/partners) ![Reseller Partners](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ![Partner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ![Partner](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ![Partner](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ![Partner](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ![Partner](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ![Partner](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ![Partner](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ![Partner](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ![Partner](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ## Reseller Benefits Join our reseller program and unlock revenue opportunities with comprehensive support and competitive commission structures. ### Competitive Commissions Earn attractive commission rates on all TestingBot subscriptions you refer, with performance-based bonuses for top performers. ### Dedicated Support Get priority access to our partner success team for sales support, technical questions, and customer assistance. ### Sales & Marketing Materials Access to professional sales collateral, presentations, case studies, and co-branded marketing materials. ### Training & Certification Comprehensive product training, sales certification programs, and ongoing education to maximize your success. ### Partner Portal Access to a comprehensive partner portal with commission tracking, customer management, and resource library. ### Partner Recognition Top performers receive recognition awards, conference invitations, and exclusive networking opportunities. ## Who We're Looking For We partner with organizations that share our commitment to quality and customer success. There is no partnership fee. ### Ideal Partner Profile - Software consultancies and development agencies - QA and testing service providers - DevOps and infrastructure consultants - Technology solution providers ## Apply to Become a Reseller Partner Ready to join our reseller program? Fill out the form below and our partnerships team will review your application. Company Name \* Email Address \* Tell us about your business \* Submit Application --- URL: https://testingbot.com/open-source # Free Testing for Open-Source Projects We think it's important to support open-source projects. That's why TestingBot offers an Open-Source plan which is **completely free** and offers **Unlimited Testing** with **2 concurrent tests**. ## Sign up for an Open Source account Please [Sign Up](https://testingbot.com/users/sign_up) first for a free trial. Once logged in, you will be able to submit a request on this page to convert your account to an open-source account. ### Browser/OS Combinations Run your Automated tests on [+5200 Browser/device combinations](https://testingbot.com/support/web-automate/browsers). Make sure your project works on all major browsers and devices. ### CI Testing Using [Travis-CI](https://testingbot.com/support/integrations/ci-cd/travis-ci), [Circle CI](https://testingbot.com/support/integrations/ci-cd/circleci) or any other Continuous Integration system to build and test your project? It's easy to use TestingBot in combination with any CI system. Simply modify your tests to use TestingBot's Selenium grid. ### Video/Screenshots/Meta-Data With every test you have access to the video showing the test, screenshots and additional meta-data (log files). We provide all these assets to make sure you can easily debug any potential problems during your tests. ### Status Badges & Matrix We provide [status badges](https://testingbot.com/support/other/status-badges) to display your test results on your project's website. Together with status badges, we also offer a badge that displays on which browsers your test succeeded/failed: [Browser Matrix](https://testingbot.com/support/other/browser-matrix) . --- URL: https://testingbot.com/about # About Us Founded in 2011, TestingBot aims to provide an easy-to-use platform for cross-browser and mobile testing. By leveraging the power of cloud computing, we can scale effortlessly to meet your testing needs. We offer flexible plans tailored for both startups and large enterprises, enabling you to test your website across hundreds of real browser and mobile device combinations. Together with **excellent customer service** , we're confident you will enjoy testing your websites with TestingBot. ![Helping developers and teams test. Reliably and at scale.](https://testingbot.com/assets/about/bg-2e0825c48447a2dbdefc8bb7e4bfe93c3fa7d218def5e88141411eb056d2c813.jpg) ## Trusted by some of the world's most innovative companies ## Helping developers and teams test. Reliably and at scale. TestingBot provides a powerful online testing grid with a wide range of real browsers and physical mobile devices. Our entire infrastructure is hosted in multiple European data centers, located in Belgium, Germany and Finland, ensuring optimal security, performance and reliability. At TestingBot, we take pride in delivering a stable, fast and secure testing environment for our customers. +6 million Tests each month 99.99% Uptime 12,000 New users annually ## Our journey TestingBot was founded in 2011 to solve a personal need: the founder wanted an easy way to run automated tests using Selenium on a website. Automated web testing was a tedious task, and the only solution was to set up a Selenium Grid on your own server. We wanted to change that and started TestingBot to provide a simple solution for automated web testing. Over the years, we've continuously expanded our platform with new features. Explore the timeline below for a complete overview of our journey. 1. 2011 🚀 TestingBot is released to the public as one of the first cloud-based Selenium grids. 2. 2012 Realtime manual testing was added for Desktop browsers. 3. 2013 🖥️ macOS based testing was released: the first company providing test access to remote Safari browsers. 4. 2014 iOS Simulators & Android Emulators are added for mobile testing. 5. 2015 TestingBot Tunnel is released: test websites running on your own computer or private network. 6. 2016 📱 We make our real device farm available to the public. Test your website on physical iOS and Android devices. 7. 2017 🗺️ This year we added geolocation testing, headless testing and various integrations with Slack, TeamCity etc. 8. 2018 We launch codeless automation. Import recorded tests from Selenium IDE and run the tests at specific intervals. 9. 2019 Live App Testing is launched: test your mobile app manually on (physical) mobile devices. 10. 2020 📈 Introducing Test Analytics: keep track of your test analytics. Release Cypress automation support, run your Cypress tests on TestingBot. 11. 2021 We've added Puppeteer Playwright testing to our features. Connect your Puppeteer scripts to the remote TestingBot browser grid. 12. 2022 Android Espresso and XCUITest support. Run tests against native apps on TestingBot's device grid. 13. 2023 Connect your Playwright scripts to the remote TestingBot browser grid. 14. 2024 🔎 Visual Regression Testing is launched: compare snapshots of your website or mobile app against baselines. 15. 2025 ✨ Introducing AI-based testing: describe in natural language what you would like to test. TestingBot will monitor your website for failures. ## Our team ![Jochen](https://testingbot.com/assets/about/avatarj_300-2d6040c8da7195c628409e9c307f78c9a3350ed4378a7506b14b4cfab353b291.webp) #### Jochen Founder ![Laura](https://testingbot.com/assets/about/avatarl_300-9016c575ff384e5d4e40b185204942c8d6828ec793649b1c3f2309da1c7a0bc6.webp) #### Laura Support ![Sander](https://testingbot.com/assets/about/avatars_300-6ba3ad8b8a51453c3ac05fe1855e4c7ccee9c139a1333329d21775721db26f72.webp) #### Sander Marketing ## Want to join our team? Interested in working on exciting technologies? [We're hiring](https://testingbot.com/careers) --- URL: https://testingbot.com/contact/new # Contact TestingBot If you need support, have questions, or are interested in purchasing a plan, feel free to reach out — we'll get back to you promptly. Name Email Message Send message [Book a Demo](https://testingbot.com/demo) Address TestingBot Vlinderhof 18 9180 Moerbeke Belgium VAT. BE 0842.864.474 Support/Sales Phone: +1 (855) 410-0024 Slack: [#help](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) ## Frequently Asked Questions ### What does the TestingBot service offer? TestingBot provides a service to test your website on multiple browsers and operating systems, automatically or manual. Similarly, you can test your mobile apps on multiple devices, making sure the app works on a wide variety of end-user mobile devices. ### Does TestingBot offer a free trial? You can [sign up](https://testingbot.com/users/sign_up) for a free trial of 28 days, with 60 minutes of free testing. ### I have a technical question, how can I reach out? Feel free to contact us with any questions using the form above. Additionally, we have extensive examples and troubleshooting tips in our [documentation](https://testingbot.com/support) section. --- URL: https://testingbot.com/careers # Careers Join our team in maintaining, optimizing and improving our testing cloud. ![Helping developers and teams test. Reliably and at scale.](https://testingbot.com/assets/about/bg-2e0825c48447a2dbdefc8bb7e4bfe93c3fa7d218def5e88141411eb056d2c813.jpg) ## Open Positions - [Technical Content Writer](https://testingbot.com#writer) ## Technical Content Writer TestingBot is looking for a technical content writer, with experience in Selenium, Cypress, Puppeteer and Playwright. You will be adding content to our [Blog](https://testingbot.com/blog) and [Resources](https://testingbot.com/resources) section. ### Responsibilities - Write articles, tutorials and courses about Selenium, Cypress, Puppeteer and Playwright. - Research interesting topics to write about, related to the online testing ecosystem. - Add code examples, screenshots and tips & tricks to the articles you write. ### Key Skills - English writer - Previous content writing experience - Faultless grammar and spelling - IT technical knowledge an advantage, especially if you have knowledge about either of these topics: Selenium, Cypress, Puppeteer or Playwright - Excellent attention to detail ### Benefits - Competitive salary - Flexible schedule - Work from home (remotely) Interested? Please send us a brief introduction and resume. [Apply now](https://testingbot.com/contact/new) --- URL: https://testingbot.com/terms # Terms of Service PLEASE READ CAREFULLY. THESE TERMS AND CONDITIONS ("THE AGREEMENT") IS A LEGALLY BINDING AGREEMENT BETWEEN YOU ("YOU" OR "YOUR") AND TESTINGBOT. ("TESTINGBOT", "WE" OR "OUR"). BY CHECKING THE APPROPRIATE BOX INDICATING THAT YOU AGREE DURING REGISTRATION OR OTHERWISE ACCESSING THE TESTINGBOT WEBSITE, SERVICES, SOFTWARE OR MATERIALS (COLLECTIVELY THE "SERVICE"), YOU ARE INDICATING THAT YOU HAVE READ THIS AGREEMENT, THAT YOU UNDERSTAND IT, AND THAT YOU CONSENT TO BE BOUND BY ALL OF ITS TERMS AND CONDITIONS. IF YOU DO NOT AGREE WITH ALL OF THE FOLLOWING TERMS AND CONDITIONS, PLEASE DO NOT CONTINUE THE REGISTRATION PROCESS OR USE THE SERVICE. IF YOU WISH TO USE TESTINGBOT AS AN EMPLOYEE, CONTRACTOR, OR AGENT OF A CORPORATION, PARTNERSHIP OR SIMILAR ENTITY, THEN YOU MUST BE AUTHORIZED TO SIGN FOR AND BIND THE ENTITY IN ORDER TO ACCEPT THE TERMS OF THIS AGREEMENT. THE LICENSES GRANTED AND SERVICES PROVIDED UNDER THIS AGREEMENT ARE EXPRESSLY CONDITIONED UPON ACCEPTANCE BY SUCH AUTHORIZED PERSONNEL. This End User License Agreement ("Agreement") is entered into by and between TestingBot and the customer (individual or entity) that has procured the TestingBot products or services for use as an end user ("Customer"). "Effective Date" means the date on which accepts the terms and conditions of this Agreement. TestingBot reserves the right, at its sole discretion, to modify or replace this Agreement, or change, suspend, or discontinue any TestingBot Product(s) or Service Descriptions (as those terms are defined below), including without limitation, the availability of any feature, database, or content) at any time by posting a notice on the TestingBot Product(s) or by sending you an email. It is your responsibility to check this Agreement periodically for changes. Your continued use of any TestingBot Product following the posting of any changes to this Agreement constitutes acceptance of those changes. ## 1. Provision of Products Welcome to TestingBot.com. We provide our customers with online software-as-a-service/platform-as-a-service products. We use Selenium, an open-sourced browser testing framework to test websites in multiple browsers in an automated way. We offer several plans according to the needs of the customer. Each plan is provided on a subscription basis for a set term designated at the time of purchase (each, as “Subscription Term”). Customer shall purchase and TestingBot shall provide the specific product and plan as specified at the time of purchase. Some elements of the Service are available to any User, while other elements ("Subscription Services") are only available to Users who have purchased a subscription from TestingBot according to these terms and conditions. TestingBot may at any time, in its sole discretion, change a freely available element of the Service to a Subscription Service, and vice versa. TestingBot may, it its sole discretion, offer Users a one-time, free trial period during which you may use Subscription Service(s) for free. The time period of any such free trial period may vary from time to time, and will be indicated at the time you register as a User. Please note that TestingBot does not provide any internet connectivity services, nor does TestingBot provide any computer equipment for Users. You are entirely responsible for securing and paying for any such services and equipment, and for ensuring that such services and equipment meet the minimum requirements for the use of the Services. General Restrictions; Acceptable Use. Customer shall not: (a) rent, lease, copy, provide access to or sublicense any TestingBot Product to a third party; (b) use any TestingBot Product to provide or incorporate any TestingBot Product into any product or service provided to a third party, (c) reverse engineer, decompile, disassemble, or otherwise seek to obtain the source code or non-public APIs to TestingBot Products, including the Video Playback, except to the extent such restriction is prohibited by applicable law (and only upon advance notice to TestingBot), (d) modify any TestingBot Product or any Documentation, or create any derivative product from any of the foregoing, (e) remove or obscure any proprietary or other notices contained in any TestingBot Product (including any reports or data printed from TestingBot Products) or (f) publicly disseminate information regarding the performance of TestingBot Products. ## 2. Accounts/Customer Data You may establish one (1) User account (the "Account") per email address you supply to TestingBot. You may not share the Account with anyone. You are liable for all uses of the Account. If you would like to have several accounts for co-workers or friends, please consider using a sub-account. Storage of Customer Data. TestingBot does not provide an archiving service. TestingBot agrees only that it shall not intentionally delete any Customer Data which is less than 30 days old from TestingBot Products prior to termination of Customer’s applicable Subscription except as directed by Customer or its Permitted Users. TestingBot expressly disclaims all other obligations with respect to storage. If specified at the time of purchase, TestingBot may charge Customer a fee for storing the Customer Data. ## 3. Registration During the registration process prior to using the Service, you may be requested to provide certain information (e.g. your birthdate, gender, zip code, name, e-mail address, country or territory of residence, and for paid services, credit card and billing information, such as your telephone number), and you agree to provide true, accurate, current and complete information about yourself as prompted by such process (such information being "Personal Information"). If you open an Account, and any of your Personal Information changes (e.g., new credit card number, expiration date, new address or email address, new phone number, etc.), you must update that information in your Account. ## 4. Subscription Services If you elect to subscribe to Subscription Services, the fee therefor will be the price specified at the time of purchase. You hereby agree to pay all charges incurred by the Account, including applicable taxes, in accordance with billing terms for access to the Service that are in effect at the time that the fee or charge becomes payable. Your right to access the Service is subject to any limits established by TestingBot or by your credit card issuer, billing service, or other payment methods authorized by TestingBot. TestingBot may, in its sole and absolute discretion, suspend or terminate your access to the Service and disable or delete the Account, if: (i) payment cannot be charged to your credit or debit card; or (ii) your charge is returned to TestingBot for any reason. If at any time you have a balance due on the Account, you agree that TestingBot can charge these unpaid fees to your credit card or debit them from your debit card, as applicable. You agree to reimburse TestingBot for all costs and expenses incurred by TestingBot in collecting payment due hereunder, including without limitation all bank or service charges, and any reasonable attorneys' fees. By subscribing to any Subscription Service you are representing to us that you are authorized to use the credit card you submit for payment. You agree to take such steps as are appropriate to ensure such compliance and will indemnify and hold TestingBot and TestingBot's affiliates and distribution and syndication partners harmless from any breach of this Agreement. Your subscription will last for the period chosen in the subscription process (the "Term"). Unless notifying us of your decision to terminate your subscription, your subscription will automatically be renewed at the end of each Term according to the then-current billing terms. TestingBot reserves the right to change the amount of, or basis for determining, any fees it charges, and to institute new fees, effective immediately upon notice to you. You may cancel your automatic membership renewal by contacting info@testingbot.com . Cancellation of your subscription will take effect upon the end of the then-current Term, at which time you will no longer have access to any Subscription Services. Our payment provider (Stripe or FastSpring) will automatically renew your paid subscription. Payment details such as your credit card number are not saved on this website. ## 5. TestingBot Materials The Service may require that you install plugins to report back test results to TestingBot. That software, and all new versions, updates, upgrades, bug fixes, modifications and derivative works that TestingBot may make available from time to time are referred to collectively as the "Software." All Software, designs, text, images, photographs, illustrations, audio clips, video clips, artwork, graphic materials, other copyrightable elements, and the selection and arrangements thereof, and all trademarks, service marks, trade dress, trade names, logos and designs and all intellectual property rights therein, provided by TestingBot via the Service (collectively the "Materials") are the property of TestingBot and/or its business partners, affiliates, assigns, licensors or other respective owners and are protected by intellectual property laws, including without limitation, U.S. and international patent, copyright and trademark laws. TestingBot may include in some Materials or in conjunction with your User Supplied Content third party advertisements that appear or are played when those Materials or User Supplied Content are viewed. You hereby consent to the display and playback of these advertisements in conjunction with your User Supplied Content. To the extent you elect to use or access TestingBot Materials or User-Supplied Content from other Users, you also consent to the display of advertisements in those Materials and that User Supplied Content. Content generated during testing like logs, screenshots and videos will stay available for 30 days. After this period, TestingBot will remove the content. ## 6. License from TestingBot Subject to all of the terms and conditions of this Agreement, TestingBot hereby grants you a personal, limited, non-exclusive, non-transferable, revocable right to (a) view or play back Materials on, your compatible computer or device. All rights not expressly granted to you are reserved. For the avoidance of doubt, your use of the Service and the Materials is under license and will terminate if this Agreement terminates, regardless of whether the relevant Service or Materials is free or you have paid for it; you will not obtain any ownership interest in any Materials through this Agreement or otherwise. ## 7. Usage Restrictions You agree not to use, download, reproduce, modify, create derivative works from, display, perform, publish, distribute, disseminate, transmit, broadcast or circulate any Materials to any third party, except as expressly authorized by TestingBot in connection with the Service. The source code and/or object code to the Materials contains confidential and trade secret information belonging to TestingBot and its licensors, and you shall at all times take reasonable steps to protect the confidentiality of such information. You further agree that you will not disassemble, decompile or reverse engineer the Materials (except to the extent that this restriction is expressly prohibited by law, and then only upon providing TestingBot with prior written notice and opportunity to respond). Any unauthorized or prohibited use may subject the offender to civil liability and criminal prosecution under applicable federal and state laws. As between you and TestingBot, TestingBot owns all elements of the Account. Except as specifically permitted and enabled within the Service, you may not transfer your Account, or any component of your User-Supplied Content to any other person. Through the use of the Service you may not impair or violate the rights of TestingBot or any other party with respect to trademarks, logos, or other intellectual property or rights. You may not display or perform Materials or User Supplied Content in a manner or in a context that is, in TestingBot's sole discretion, unlawful, misleading, defamatory, infringing, libelous, disparaging, obscene, an endorsement of any unrelated product or service, an unauthorized parody, or otherwise objectionable. ## 8. Code of Conduct You may not: (i) post any User Supplied Content that is illegal, abusive, deceptive, pornographic, obscene, defamatory, slanderous, offensive, or otherwise inappropriate or harmful to any person (including any minor) or entity; (ii) sell, rent, lease, or otherwise assign any rights to any Materials or Service to any third party; (iii) remove any proprietary notices or labels on the Materials or Service; (iv) use the Materials or Service in conjunction with any device or service designed to circumvent technological measures employed to control access to, or the rights in, any content protected by the copyright laws of any jurisdiction; (v) use the Materials or Service for any commercial or illegal purpose or to harm minors in any way; (vi) use the Materials or Service to invade the privacy of, or obtain personal information about, any User, or to obtain a list of Users, or to access or use any User's User Supplied Content in a manner not specifically authorized by such User; (vii) except as expressly permitted by TestingBot, copy, modify, erase or damage any Materials or information contained on any TestingBot or third party servers; (viii) use the Materials or Service to violate any law or legal right of any third party, including any publicity or privacy right, copyright, other intellectual property right, or any contractual, fiduciary or confidentiality obligation or duty, or to take any action that is harassing, libelous, defamatory, abusive, tortious, threatening, harmful or otherwise objectionable; (ix) use the Materials or Service to post or transmit any unsolicited advertising, campaigning or promotional materials or to send any Materials from an anonymous or false address; (x) access or use any password protected, secure or non-public areas of the Service except as specifically authorized in writing by TestingBot (unauthorized individuals attempting to access these areas of the Service may be subject to prosecution); (xi) distribute any software viruses or other computer code designed to interfere with the functionality of the Service or any computer systems, software or hardware; (xii) use any data mining, robots, or similar data gathering, spoofing, or extraction tools in connection with the Materials Service; (xiii) mislead other Users or third parties as to your identity or to the origin of a message or content; or (xiv) frame or link to the Service or Materials except as expressly permitted in writing by TestingBot. ## 9. Objectionable or Explicit Content TestingBot has the right, but not the obligation, to monitor, modify and/or remove any Materials and/or User Supplied Content in the Service. TestingBot may monitor, modify and remove any Materials and/or User Supplied Content in its sole discretion. TestingBot is not responsible to you for any content or materials constituting all or part of any Materials, any User Supplied Content, or any other aspect of the Service that you might find objectionable. By viewing the Service, you may be exposed to content that you consider offensive. You take sole responsibility for such exposure. ## 10. Privacy For information regarding TestingBot's use of information collected in connection with the Service, please refer to the [TestingBot Privacy Policy.](https://testingbot.com/privacy) ## 11. Active Participation; Storage and Bandwidth Limits If you do not have a currently active subscription to the Subscription Service, a condition of your access to the Service is your "Active Participation" in the Service. Active Participation is defined as accessing the Service, including displaying Materials or sending User Supplied Content through the Service, at least once every 180 days. If you do not maintain Active Participation, TestingBot may, with or without providing you with notice, terminate your Account (or any part thereof) and/or your use of the Service, and may remove and discard any content, including any of your User Supplied Content and any related Materials within the Service. Additionally, with or without providing you with notice, we may place a maximum limit on the amount of User Supplied Content that you are allowed to upload into the Service, or the maximum bandwidth that you may utilize each day. We may change these limits in our sole discretion upon providing you with notice. If you exceed these limits, we may refuse to accept and/or remove any User Supplied Content, or we may suspend certain functions of the Service for your Account. ## 12. Changes to the Agreement We reserve the right, at our sole discretion, to change, modify or otherwise alter these terms and conditions at any time. Such changes and/or modifications shall become effective immediately upon posting. Please review the terms and conditions periodically. If you do not agree to be bound by (or cannot comply with) the Agreement as amended, your only remedy is to cancel your TestingBot Account and to cease using the Service. You will be deemed to have accepted the Agreement as amended thirty (30) days after the amended agreement is posted if you continue to use the Service. All other terms of this Agreement will continue in effect. ## 13. Notices TestingBot may provide you with any notices under this Agreement by means of a posting on the Service, by e-mail, or by sending a message to you through the Service.    A. A physical or electronic signature of the owner (or person authorized to act on behalf of the owner) of an exclusive right that is allegedly infringed.    B. Specific identification of the copyrighted work claimed to have been infringed, or if multiple copyrighted works are covered by a single notification, a list of each copyrighted work claimed to have been infringed.    C. Information related to the work(s) reasonably sufficient for TestingBot to promptly locate the work (e.g. title of work, location within the Service, etc.).    D. Information reasonably sufficient to permit TestingBot to directly contact the complaining party, such as a complete name and address, telephone number, and an email address.    E. A statement that the complaining party has a good TestingBot belief that use of the work(s) in the manner complained of is not authorized by the copyright owner, its agent, or the law.    F. A statement requesting that TestingBot take a specific act with respect to the alleged infringement (e.g., removal, access restricted or disabled), and    G. A statement that the information in the notification is accurate, and under penalty of perjury, that the complaining party is authorized to act on behalf of the owner of an exclusive right that is allegedly infringed. ## 14. Trademarks Except as expressly set forth in this Agreement, all trademarks, service marks, trade names, domain names, slogans, logos, and other indicia of origin that appear on or in connection with the Service and Materials are the property of TestingBot and/or its affiliates and licensors. You may not copy, display or use any of these marks without prior written permission of the mark owner. ## 15. International You agree to abide by U.S and other applicable export control laws and not to transfer, by electronic transmission, the Service, or otherwise, any content or software subject to restrictions under such laws to a national destination or person prohibited under such laws. ## 16. Promotions and Advertising TestingBot and/or its business partners may present advertisements and promotional materials on or through the Service. Your participation in any TestingBot promotional event is subject to the terms and conditions associated with that event. Your correspondence or business dealings with, or participation in promotions of, any third-party advertisers on or through the Service, including payment and delivery of related goods or services, and any other terms, conditions, warranties or representations associated with such dealings, are solely between you and such third-party. You agree that neither TestingBot nor its business partners shall be responsible or liable for any loss or damage of any sort incurred as the result of any such dealings or as the result of the presence of such third parties on the Service. ## 17. The Website and Links to Third Party Sites The Website means this web site, as accessed by any of the following domain names: testingbot.com, \*.testingbot.com and any web site owned or controlled by TestingBot (except as otherwise provided on such other site). However, the Website does not refer to any other web site linked to or from the Website, or to any third party site on which the Service may appear. The Service may present links to retailers and/or other third-party websites not owned or operated by TestingBot. Neither TestingBot nor its business partners are responsible for the availability of these outside sites or their contents. You understand and agree that neither TestingBot nor its business partners are responsible or liable, directly or indirectly, for any damage or loss caused or alleged to be caused by or in connection with your use of or reliance on any content of any such site or goods or services available through any such site or from any such advertiser. You should direct any concerns regarding these third-party sites to those sites' administrators. ## 18. Modifications to Service and Materials TestingBot may, without liability or obligation, in its sole discretion and at any time: (i) make modifications to, or discontinue, any Materials and/or the Service, including deleting any Downloaded Materials we may have placed on your computer, with or without providing you with notice (except as we may expressly agree to provide you with notice elsewhere in this Agreement); and/or (ii) require you to use modified Materials and/or Service (e.g. Software updates) in order to have continued access to the Service and Materials. The modifications may result in certain Materials being unavailable, or incompatible with certain devices. Other Users may similarly delete or cease offering their User Supplied Materials at any time without notice. Upon TestingBot giving you notice, you shall promptly cease the use of, and destroy, all copies of any specified Materials, or otherwise modify your usage as directed by TestingBot. You agree that neither TestingBot nor the TestingBot Affiliates shall be liable to you or to any third party for any modification, suspension or discontinuance of the Service or Materials. ## 19. Remedies You understand and agree that any unauthorized use of the Service or the Materials would result in irreparable injury to TestingBot and/or the TestingBot Affiliates for which money damages would be inadequate, and in such event TestingBot and the TestingBot Affiliates, shall have the right, in addition to other remedies available at law and in equity, to immediate injunctive relief against you. Nothing contained in this paragraph or elsewhere in this Agreement shall be construed to limit remedies or relief available pursuant to statutory or other claims that TestingBot and the TestingBot Affiliates may have under separate legal authority, including but not limited to, any claim for intellectual property infringement. You understand and agree that your cancellation of your Account is your sole right and remedy with respect to any dispute with TestingBot. You can cancel your Account by delivering notice to TestingBot at info@testingbot.com. ## 20. Indemnity You agree to indemnify, and hold harmless, TestingBot, the TestingBot Affiliates, and each of their respective officers, directors, employees, agents, licensors, representatives, and third party providers from and against all claims, actions, demands, causes of action, and other proceedings, and all losses, expenses, fees, fines, damages and costs, including reasonable attorneys' fees and court costs, arising out of or relating to your breach of this Agreement or improper use of the Service or Materials. TestingBot reserves the right to assume, at its sole expense, the exclusive defense and control of any matter subject to indemnification by you, in which event you will fully cooperate with TestingBot in asserting any available defenses. ## 21. Suspension or Termination TestingBot may, in its sole discretion, terminate this Agreement or suspend your Account at any time with or without notice to you in the event that you breach (or TestingBot reasonably suspects that you have breached) any provision of this Agreement. If TestingBot terminates this Agreement, or suspends your Account for any of the reasons set forth in this paragraph, TestingBot shall have no liability or responsibility to you, and you agree that you forfeit any amounts you have paid TestingBot. TestingBot may terminate this Agreement and your Account for any reason or no reason at the end of the then-current Term by providing notice to you. You may cancel your Account (including Subscription Services) at any time by contacting info@testingbot.com. All fees paid and charges made prior to termination as provided herein are nonrefundable, including any advance charge or payment for the subscription term during which you terminate your subscription. Termination of your subscription shall not relieve you of any obligations to pay accrued charges. Upon termination of this Agreement for any reason, all of your rights to use the Service and materials shall immediately terminate, and you shall immediately cease using and destroy all Materials. ## 22. Disclaimers You understand and agree that your use of the Service and the Materials is at your own sole risk. TestingBot is not responsible or liable for any infections or contamination of your system, or delays, inaccuracies, errors, or omissions arising out of your use of the Service or Materials. The entire risk as to the quality, accuracy, adequacy, completeness, correctness and validity of any Materials rests with you. THE SERVICE AND THE MATERIALS ARE PROVIDED "AS IS" AND "AS AVAILABLE," AND WITHOUT WARRANTY BY TESTINGBOT AND THE TESTINGBOT AFFILIATES, AND, TO THE MAXIMUM EXTENT ALLOWED BY APPLICABLE LAW, TESTINGBOT AND THE TESTINGBOT AFFILIATES EXPRESSLY DISCLAIM ALL WARRANTIES, EXPRESS AND IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY OF NONINFRINGEMENT. THERE IS NO WARRANTY THAT THE SERVICE OR THE MATERIALS WILL MEET YOUR REQUIREMENTS, OR THAT YOUR ACCESS TO THE SAME WILL BE UNINTERRUPTED OR ERROR-FREE. TESTINGBOT AND THE TestingBot AFFILIATES DO NOT WARRANT, GUARANTEE, OR MAKE ANY REPRESENTATIONS REGARDING THE USE OR THE RESULTS OF THE USE OF THE SERVICE OR THE MATERIALS WITH RESPECT TO PERFORMANCE, ACCURACY, RELIABILITY, SECURITY CAPABILITY, CURRENTNESS OR OTHERWISE. YOU WILL NOT HOLD TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES RESPONSIBLE FOR ANY DAMAGES THAT RESULT FROM YOU ACCESSING THE SERVICE OR USING THE SERVICE AND/OR THE MATERIALS. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY ANY PERSON SHALL CREATE A WARRANTY IN ANY WAY WHATSOEVER RELATING TO TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES. UNDER NO CIRCUMSTANCES SHALL TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES BE LIABLE FOR ANY UNAUTHORIZED USE OF THE SERVICE AND/OR THE MATERIALS. ## 23. LIMITATION OF LIABILITY TO THE FULLEST EXTENT PERMISSIBLE PURSUANT TO APPLICABLE LAW, UNDER NO CIRCUMSTANCES SHALL TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES BE LIABLE TO YOU FOR ANY CONSEQUENTIAL, INCIDENTAL, INDIRECT, SPECIAL OR SIMILAR DAMAGES (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, AND THE LIKE) ARISING OUT OF THE USE OR INABILITY TO USE THE SERVICE AND/OR THE MATERIALS, EVEN IF TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES, HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU. TO THE EXTENT THAT IN A PARTICULAR CIRCUMSTANCE ANY DISCLAIMER OR LIMITATION ON DAMAGES OR LIABILITY SET FORTH HEREIN IS PROHIBITED BY APPLICABLE LAW, THEN, INSTEAD OF THE PROVISIONS HEREOF IN SUCH PARTICULAR CIRCUMSTANCE, TESTINGBOT AND/OR THE TESTINGBOT AFFILIATES, SHALL BE ENTITLED TO THE MAXIMUM DISCLAIMERS AND/OR LIMITATIONS ON DAMAGES AND LIABILITY AVAILABLE AT LAW OR IN EQUITY BY SUCH APPLICABLE LAW IN SUCH PARTICULAR CIRCUMSTANCE, AND IN NO EVENT SHALL SUCH DAMAGES OR LIABILITY EXCEED TWENTY FIVE DOLLARS ($25). Notwithstanding the foregoing, in no event shall TestingBot's liability to you for any and all claims, damages, losses, and causes of action (whether in contract, tort or otherwise) exceed the amount paid by you, if any, for accessing the Service. ## 24. Claims and Arbitration Any action hereunder by a User must be brought, if at all, within one (1) year from the accrual of the cause of action. You agree that the all disputes and claims arising out of, or relating to, this Agreement, the Service or Materials, your use of the Service or Materials (including the arbitrability of any claim or dispute and the enforceability of this paragraph), or to any other alleged act or omission by you or TestingBot, shall be determined exclusively by final and binding arbitration. Provided however, that you agree that the terms of this paragraph do not apply to any breach or alleged breach of the ownership or license rights of TestingBot or any of its licensors with respect to any Materials and/or Service, or your (or any third party's) misuse of the Materials and/or Service, and that, in the event of any such breach of alleged breach, TestingBot and its licensors will be irreparably harmed and entitled to equitable and injunctive relief in addition to all other remedies provided by this Agreement or available at law. Except as expressly set forth above in this paragraph, you and TestingBot may litigate in court only to compel arbitration under this Agreement or to confirm, modify, vacate or enter judgment on the award rendered by the arbitrators. To the extent that you have breached or have indicated your intention to breach this Agreement in any manner which violates or may violate TestingBot's or any of its licensor's intellectual property rights, or may cause continuing or irreparable harm to TestingBot (including, but not limited to, any breach that may impact TestingBot's or its licensor's intellectual property rights, or a breach by reverse engineering), TestingBot may seek injunctive relief, or any other appropriate relief, in any court of competent jurisdiction. To the fullest extent permitted by applicable law: no arbitration under this Agreement shall be joined to an arbitration involving any other current or former licensee of TestingBot, whether through class arbitration proceedings or otherwise; no finding or stipulation of fact in any other arbitration, judicial or similar proceeding may be given preclusive or collateral estoppel effect in any arbitration hereunder (unless determined in another proceeding between you and TestingBot); and no conclusion of law in any other arbitration may be given any weight in any arbitration hereunder (unless determined in another proceeding between you and TestingBot). ## 25. Miscellaneous This Agreement and any other terms or documents referred to herein represent your entire agreement with TestingBot with respect to your use of the Service and Materials. As used in this Agreement the term "licensor" shall not refer to the person at that time entering into the Agreement. You understand and agree that, except as expressly set forth herein, this Agreement is not intended to confer and does not confer any rights or remedies upon any person other than the parties to this Agreement. If any part of this Agreement is held invalid or unenforceable, that portion shall be construed in a manner consistent with applicable law to reflect, as nearly as possible, the original intentions of the parties, and the remaining portions shall remain in full force and effect. TestingBot's failure to pursue any available claim or defense pursuant to this Agreement or otherwise will not be a waiver of such claim or defense. The headings used in this Agreement are for convenience only, and will have no effect on the interpretation or legal enforceability of the terms herein. This Agreement is personal to you and may not be transferred, assigned or delegated to anyone. Any attempt by you to assign, transfer or delegate this Agreement shall be null and void. Last updated: May 9, 2017 --- URL: https://testingbot.com/privacy # Privacy Policy TestingBot knows that you care how information about you is used and shared, and we appreciate your trust that we will do so carefully and sensibly. By visiting testingbot.com, you are accepting the practices described in this Privacy Policy. TestingBot knows that you care how information about you is used and shared, and we appreciate your trust that we will do so carefully and sensibly. We process personal information contained in Customer Data on behalf of our customers under the terms and conditions of our [TestingBot Customer Data Processing Addendum](https://trust.testingbot.com). - [What's your policy about Cookies?](https://testingbot.com#cookies) - [What personal information does TestingBot gather?](https://testingbot.com#personal) - [Which information do you share?](https://testingbot.com#information) - [What Data Subject Rights Do I Have?](https://testingbot.com#rights) - [How Long Do We Retain Your Personal Data?](https://testingbot.com#duration) - [Is my information safe on this website?](https://testingbot.com#secure) - [Which information can I access?](https://testingbot.com#access) - [Are children allowed to use TestingBot?](https://testingbot.com#children) - [How can I remove all my information from TestingBot?](https://testingbot.com#delete) - [Who is the Data Controller?](https://testingbot.com#controller) - [What Are Our Legal Bases for Processing Personal Data?](https://testingbot.com#legal) - [Conditions of use, notices, and revisions](https://testingbot.com#changes) - [Implemented Technologies](https://testingbot.com#technologies) ## What's your policy about Cookies? Please consult our [Cookie Policy](https://testingbot.com/cookie-policy). ## What personal information does TestingBot gather? The information we learn from customers helps us personalize and continually improve your experience at testingbot.com. During signup, you are asked for your first name and last name, together with an e-mail address. When upgrading your plan, you may be asked for a telephone number and address by our billing provider. Information from Other Sources: We might receive information about you from other sources and add it to our account information. You are not required to provide any personal data to us, but if you do not provide any personal data to us, you may not be able to use certain features of our Services... ## Which information do you share? - **Subcontractors, sub-processors and service providers:** We share your firstname, lastname and email address with our payment providers Stripe and PayPal and with our online chat widget Drift. - A third party, in order to enforce or defend our rights, or to address financial or reputational risks. - A third party to respond to requests relating to a criminal investigation or alleged or suspected illegal activity. - Other recipients where we are authorised or required by law to do so. - A purchaser or prospective purchaser of all or part of our assets or our business... ## What Data Subject Rights Do I Have? - **Right of access:** You have the right to obtain from us confirmation as to whether your personal data is being processed... - **Right to rectification:** You have the right to obtain from us the rectification of inaccurate personal data... - **Right to erasure:** You have the right to ask us to erase your personal data... - **Right to restriction of processing:** You have the right to request restriction of processing... - **Right to data portability:** You have the right to receive your personal data in a structured, commonly used... - **Right to object:** You have the right to object, on grounds relating to your particular situation... - **Right to Submit Complaints:** You have a right to lodge a complaint with a supervisory authority. ## How Long Do We Retain Your Personal Data? If you register for an account on our Services, we retain your personal data for as long as you have an account with us... ## Is my information safe on this website? TestingBot uses SSL (HTTPs) on all parts of its service/website. SSL encrypts information between you and our website. Payment data is handled by our payment provider (Stripe/PayPal)... All sensitive data is encrypted in our database and in our log files. Passwords and security tokens are stripped before they are logged into our system. We will notify serious data breaches... We restrict access to Account-Related Information and other Personal Information... ## Are children allowed to use TestingBot? We do not sell products for purchase by children. If you are under 18, you may use TestingBot only with the involvement of a parent or guardian. ## Which information can I access? You can access and modify your personal information in our member area. ## How can I remove all my information from TestingBot? Please log into our member area, click "Account" and click the "Remove account" button. ## Who is the Data Controller? If you are using our Services, the data controller is TestingBot - Belgium, +1 (855) 410-0024... ## What Are Our Legal Bases for Processing Personal Data? - **Contract Performance:** We process the personal data of users of our Services as necessary to perform our contractual obligations... - **Legitimate Interests:** To provide users with a good user experience, to maintain and secure our Services... - **Legal Obligations:** If we are subject to a lawful access request, engaged in a legal proceeding... - **Consent:** If we are required to obtain your consent to send you marketing communications... - **Vital Interests:** In extenuating circumstances, we may need to process your personal data to protect the vital interests... ## Conditions of use, notices, and revisions If you choose to visit testingbot.com, your visit and any dispute over privacy is subject to this Notice... We may periodically alter this policy and our Terms of service. Please check these pages frequently to see the most recent changes. **Last updated: April 9, 2024** ## Implemented Technologies If you have any questions, complaints or remarks about this Privacy Policy, you can contact our Data Protection Officer at [info@testingbot.com](mailto:info@testingbot.com). TestingBot Attn: Data Protection Officer [info@testingbot.com](mailto:info@testingbot.com) Telephone number: +1 (855) 410-0024 [Contact TestingBot](https://testingbot.com/contact/new) --- URL: https://testingbot.com/cookie-policy # Cookie Policy TestingBot uses cookies to improve your user experience. ## What's a cookie? A cookie is a small file which is placed on your computer to remember your preferences. You can read more about cookies on [AllAboutCookies](https://allaboutcookies.org). ## How are you using cookies? When you first visit our website, our partner Google Analytics will set a cookie to track which pages you visit. Next to that, we will set a cookie to determine if you're logged in or not (session cookie). Once you log out, this cookie is destroyed. We offer online chat as a way to help you with your questions. This 3rd party provider also sets cookies to enhance your user experience. ## Cookie List Below is the list of cookies we use on TestingBot: ### Strictly Necessary Cookies These cookies are necessary for the website to function and cannot be switched off in our systems... #### Cookies used | Cookie Name | Description | Expiration | | --- | --- | --- | | \_testingbot\_gsession | Keep track of whether you're signed in on TestingBot | Until you close your browser | | remember\_user\_token | If you enabled "Remember me" during login, we will use this cookie to remember your session. | 14 days | | \_\_stripe\_mid | Used by Stripe. More info on [Stripe's Cookie Policy](https://stripe.com/cookies-policy/legal). | 1 year | ### Performance Cookies These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site... #### Cookies used | Cookie Name | Description | Expiration | | --- | --- | --- | | \_gid | Used by Google Analytics. [More info](https://www.en.advertisercommunity.com/t5/Google-Analytics-Code/Information-about-a-cookie-of-Google-Analytics-named-gid/td-p/1127468). | 30 days | | \_ga | Used by Google Analytics to identify unique sessions. | 30 days | ### Targeting Cookies These cookies may be set through our site by our advertising partners... #### Cookies used | Domain | Cookies | | --- | --- | | youtube.com | - SID - HSID - demographics - VISITOR\_INFO1\_LIVE - PREF - APISID - SSID - LOGIN\_INFO - YSC - SAPISID | | google.com | - APISID - SSID - NID - PREF - SID - SAPISID - HSID | ### Social Media Cookies These cookies are set by a range of social media services that we have added to the site... #### Cookies used | Cookie Name | Description | Expiration | | --- | --- | --- | | intercom-id-[app\_id] | Anonymous visitor identifier for the online chat functionality. | 9 months | | intercom-session-[app\_id] | Keeps track of chat sessions. Gives users access to their previous conversations and identifies them in the Messenger. | 1 week | | intercom-device-id-[app\_id] | Identifier for each unique device that interacts with the Messenger. | 9 months | This policy was last updated on October 8, 2025. Please see our [Terms & Conditions](https://testingbot.com/terms) and our [Privacy Policy](https://testingbot.com/privacy) for additional information. --- URL: https://testingbot.com/features/smart-tv-testing # Online Test Automation On Smart TVs OTT test automation on living room devices such as Apple TV, Amazon Fire TV and Chromecast with TestingBot. Manual and automated crossplatform testing on real Apple TV (tvOS) and Android TV devices. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Online Test Automation On Smart TVs](https://testingbot.com/assets/hero/smarttv-5af19a1f001b85050d5408ac75376cb652d49188245a452b9e7393e20762fd4b.svg) Trusted by some of the world's most innovative companies ## Automated Testing for Smart TV apps Run Appium tests on TV apps running on Apple TV 4K, Chromecast and more. Get access to raw video and audio generated from the Smart TV device. Test DRM-protected content, by accessing a device via manual or automated testing. [Read SmartTV Testing Documentation](https://testingbot.com/support/app-automate/smart-tv) ### Automated Testing with Appium Upload your Smart TV app and run automated tests with Appium on the remote device. ### Connect to a remote TV device Access live video and audio generated from the device, through your own browser and control the remote as if it was in your hand. ### Device Coverage Test on various devices such as Apple TV 4K, Chromecast and more. ## Frequently Asked Questions ### What competitive edge does TestingBot offer with Smart TV testing, compared to its peers? TestingBot offers both manual and automated testing of apps on Smart TVs. View DRM-protected content, hear live audio of the device under test and manually send remote control (IR signals) to the device. ### How can I test Smart TV applications on a remote Smart TV device? Simply upload your app to TestingBot Storage and pick a device to test on. TestingBot provides a high quality video and audio stream of the device. ### Manual and Automated Testing on AppleTV and Chromecast Manually control a device such as Apple TV 4K or ChromeCast device, through your own browser. Run automated tests with Appium on remote smart-tv devices. ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/manual-browser-testing # Superfast, Live Cross Browser Testing Manually control any browser in our cloud directly from your own browser. Gain instant access to real browsers and preview how your website looks and behaves across multiple platforms in real time. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Superfast, Live Cross Browser Testing](https://testingbot.com/assets/hero/live-74577b43e14815f7b41c2393c7d0f7609791714d5a39c8994dad7c9feff01841.svg) Trusted by some of the world's most innovative companies ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Test on real mobile & desktop devices Get one-click access to real browsers running on macOS, Windows and Linux platforms. Cross-browser testing made simple: switch platforms, locations and screen resolutions instantly. Test across all versions of Internet Explorer (IE8 to IE11), Edge, Chrome, Safari, Firefox and Opera. [Get started free](https://testingbot.com/users/sign_up) ## 5200+ real desktop & mobile browser combinations Test on the widest range of desktop and mobile devices in our real device cloud. We handle setup, procurement and maintenance — so you can focus entirely on testing. ### Windows, macOS & Linux One-click access to every macOS, Linux and Windows version. From Yosemite to macOS Sequoia, and Windows XP to Windows 11. We've got you covered. ### Every browser, all versions Edge, Safari, Firefox, Chrome, Opera and IE - constantly updated & instantly available. ### Security Single-Use VMs and pristine real devices, reset after each use. ### Real Android & iOS devices Test across real iPhone, iPads, Google, OnePlus, Xiaomi and Samsung phones & tabs. ### No setup & maintenance Instantly access 5200+ devices and browsers. Experience zero setup or maintenance hassles, and focus only on testing. ### Performance Our infrastructure is built for performance to eliminate test flakiness and latency. ## Take control of a device Interact with the remote mobile device, just as you would with a device in hand. Tap, scroll, zoom, swipe and more. ![Parallel Testing](https://testingbot.com/assets/features/control-device-114c527535e472dd402c03580fdb23b36ab5716387bc5448c5d6d4262219b655.jpg) ## Test in different scenarios Test your website in different scenarios, such as geolocation, resolution, network speed and device orientation. ### Resolutions Test your website in various screen resolutions, perform responsive design testing. ### Geolocation Testing Test your website from various geographical locations, test location-aware features such as currencies or locales. ### Network Speed Test response to real-world network conditions by simulating Edge, 2G, 3G & 4G network. ### Device orientation Change the orientation of the device, from portrait to landscape and vice-versa. ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/share-test-1535f5a900c01eac0ec4376daec490bb6b5af56ecb80ce59639ee2fe7d33a885.jpg) ## Report bugs & capture metadata while testing Take and annotate screenshots during a manual test, share with top tools such as Jira, Slack and more. Each manual test also comes with a video recording. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ## Frequently Asked Questions ### Do I need to install anything? No, you don't need to install anything. Simply sign up for a free account and start testing. You can interact with a remote browser, just like you would with a local browser, with your own mouse and keyboard. No need to install any plugins or software. ### Can I test with various resolutions and responsive designs? Yes, you can test with various resolutions and responsive designs. Simply change the resolution during the manual test. ### Can I hear the audio from the remote browser? Yes, TestingBot will stream the audio from the remote browser, allowing you to test applications that require audio. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/manual-mobile-testing # Live Mobile App Testing Manually control [a physical mobile device](https://testingbot.com/support/app-automate/devices) in our cloud to test your mobile app. Upload your iOS or Android app and test it on a real device, directly from your own browser. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Automated Mobile App Testing](https://testingbot.com/assets/hero/manual-app-testing-12fb4d3b5749d78078fa9929d74e109f8efe65f8af3522bdc23f4bfbab4089a6.webp) Trusted by some of the world's most innovative companies ## Reliable Device Farm Get instant access to a fast, reliable device infrastructure. ### 24/7 device availability Physical iOS and Android devices, available at any time of the day. ### Zero setup & Maintenance Focus on testing instead of worrying about setup and maintenance of a mobile device farm. ### Security Devices located in a datacenter in Europe. Each test runs on a secure and pristine device. ### Real Android & iOS devices Test across real iPhone, iPads, Google, OnePlus, Xiaomi and Samsung phones & tabs. ### Variety of devices Test on any device — flagship or budget — with support for the newest and legacy iOS and Android versions. ### Performance Our infrastructure is built for performance to eliminate test flakiness and latency. ## Take control of a device Interact with the remote mobile device, just as you would with a device in hand. Tap, scroll, zoom, swipe and more. ![Parallel Testing](https://testingbot.com/assets/features/control-device-114c527535e472dd402c03580fdb23b36ab5716387bc5448c5d6d4262219b655.jpg) ## Test native device features Access and modify device features to test your app in various real-world conditions. ### Network Simulation Test for scenarios like connectivity, fluctuating network & many more. ### Localization testing Test your apps across different timezones, languages and geolocations. ### Dark Mode Test your app's UI with a dark background to ensure a smooth user experience. ### App Orientation Test your app in the landscape or portrait mode. Switch between orientations to test your app's response. ### Audio Record and hear in realtime the audio generated on the device. ### Settings Control various settings on the device, through ADB or other. ## Control device See realtime generated logs from the remote iOS/Android device. Rotate the device, change its GPS location, modify the system language and more. Inspect the logs for errors, crashes or stacktraces. [Get started free](https://testingbot.com/users/sign_up) ![Private Device Cloud](https://testingbot.com/assets/features/manual-app-ui-87103cae76ed7710e8af70ad58a3ef37a36bf41aa29566580a5e36bcdef89cae.webp) ## Inspect your app Find locators to use in your Automated Tests. TestingBot highlights the area in your layout while you go over the different elements in the layout hierarchy. Easily locate XPath, XCUITest and Espresso locators which you can then use for Automated Testing. ![Private Device Cloud](https://testingbot.com/assets/features/inspector-f48a920e82606a3a941d6d899b27e5a85ca3e63b474155e36ab6cff7d6ed7571.webp) ## TestingBot Storage Upload your native mobile app, as an .apk or .ipa, to [TestingBot Storage](https://testingbot.com/support/api#upload) and start testing immediately. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/tb-storage-a1d1845fbed2bac0012e225de7f847431af6ffdb9dd9b6233fd3145ef3681cb9.jpg) ## Your very own Mobile Devices Choose your own iOS and Android devices. We will purchase these devices, install and configure them in our secure datacenter. These devices will be only available to you, 24x7. Private devices can be customised to your needs. Have us install specific profiles and apps, or change specific settings of the device. You decide. [Learn more](https://testingbot.com/enterprise/private-device-cloud) ![Private Device Cloud](https://testingbot.com/assets/enterprise/datacenter-d4fc366e9a4e8a106ec41e6817e21adb2aeb366a397ac258fd29ba9cd4de72c4.jpg) ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ## Frequently Asked Questions ### Should I use a real device or an emulator? TestingBot provides both emulators/simulators, as well as physical devices. Emulators are good if you want to test basic functionality, but they do not provide the same experience as a real device. We recommend using both real devices and emulators, depending on your needs. ### Where are the devices located? TestingBot offers physical devices located in Belgium (Europe). ### Which apps can I test? You can test any app that is available in the Apple App Store or Google Play Store. You can also upload your own app (.ipa or .apk) and test it on a real device. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Live Mobile App Testing documentation](https://testingbot.com/support/app-live) - [Upload your mobile app](https://testingbot.com/support/app-automate/help/upload) - [Preparing your app for testing](https://testingbot.com/support/app-automate/help/prepare) - [List of mobile devices](https://testingbot.com/support/app-automate/devices) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/ai-testing # AI Test Automation Create automated tests in a fast and easy way. Generate tests in natural language with Gen AI. Generate your tests, replay on 5200+ browsers and mobile devices. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![AI Test Automation](https://testingbot.com/assets/hero/codeless-hero-7afd44c329d9058be520bf755966ce28a6c6d7faef0bda267975991a751f8143.webp) Trusted by some of the world's most innovative companies ## AI Testing Describe in natural language what your test should do and let Gen AI create the test for you. Save time and resources from your developers and QA engineers by using AI to run tests against your website. The AI Testing Agent will convert your prompt into an automated test, which you can then schedule to run periodically on remote browsers. [Get started free](https://testingbot.com/users/sign_up) ![AI Testing](https://testingbot.com/assets/features/ai-example-44d4424ca1c77ba88be8e28a761c4e0a8f1d056761a594cbed34ed2366f0e305.jpg) ## Example AI usecases to Test Your Website Use natural language prompts to check critical elements and flows on your site, using Generative AI. ### Shopping Cart Prompt: Add a product to the shopping cart. Verify on the checkout page that the product is in the shopping cart. ### Handle OCR/Captcha's Use the AI to handle OCR and captcha's. The AI will perform the necessary actions and validations. ### Skip Locators The AI will not depend on locators such as XPath or CSS selectors. Simply define elements by their text, such as "Click the button that says 'Submit'". ### Conditional Actions The AI will be able to perform conditional actions, such as "If the login is successful, check if the user is redirected to the dashboard page". ### Verify video playback Check if a video is playing correctly on the page. The AI agent will verify the video playback and check for any errors. ### Graph Check Prompt: Check that the page contains an image of a graph showing positive growth. ### Logo Presence Prompt: Verify that the company's logo is visible in the page header. ### CTA Button Check Prompt: Confirm the presence of a “Get Started” button that links to the signup page. ### Form Validation Prompt: Ensure that submitting an empty form displays an error message. ## AI Chat Chat with the AI Test Agent and instruct it to perform actions, such as clicking buttons, filling out forms, and verifying elements on the page. Ask the AI to generate automated test scripts from the actions you specified. Export to Java, Kotlin, Python, C#, Selenium IDE, JavaScript, Ruby and more. ## Record tests Import your recorded tests from Selenium IDE. TestingBot will run the tests periodically on the remote browsers you specified. [Get started free](https://testingbot.com/users/sign_up) ![AI Testing](https://testingbot.com/assets/features/test-recorder-f95a63c80abaef9ba574444e53decc70f2c6304a9c0464339cc53637706eeeba.webp) ## AI Test Automation Run tests without writing any code on the TestingBot platform. ### Browsers & OS Select one or more browsers running on a specific operating system. Specify browser versions to target specific test environments. ### Schedule Run tests periodically; every minute, hour, day or at a custom interval. ### Alert When a test fails, you will receive email notifications or text messages. ### Reports Receive daily reports on the progress of your tests. ### Settings Set specific settings such as geolocation, screen resolution and more. ### Performance The tests will run in parallel on TestingBot's performant browser grid. ## Schedule Tests Schedule your tests to run on specific days and intervals. Set a cron format to define the exact days and hours you want your tests to run in parallel on our browsers. ![Schedule Tests](https://testingbot.com/assets/features/img-schedule-tests-5d62539793f48d4facd065f223691504c0aa9c36d3d394c2f2fa15969594f2e4.webp) ## Frequently Asked Questions ### How can I use AI to create automated tests? TestingBot allows you to use LLMs to create automated tests in natural language. Simply describe what you want to test, and the AI will generate the test for you. The AI will generate the test and instruct a remote browser to perform the necessary actions and validations. ### How can I record automated tests? You can use the official Selenium IDE browser plugin to record your test flow. The recorded test can be imported into TestingBot for execution. Once imported, you can choose the browsers and devices you want to run the test on, and schedule it to run periodically. ### What are some example AI prompts I can use to create tests? You can use prompts like "Create a test that logs into my website" or "Create a test that checks if the homepage loads correctly". Or check if an item can be added to a shopping cart - "Create a test that adds an item to the shopping cart and checks if the cart is updated correctly". ### Why should I use AI to create automated tests? You can write tests in plain English. Some customers even import their user stories from other platforms such as TestRail, PractiTest or Zephyr into TestingBot AI. It is very easy to explain and understand what is being tested. Because the TestingBot AI tests are not dependent on XPath or other brittle locators, they are ultra-stable. Customers are running hundreds of tests multiple times a day without a single failure. ### Ready to start AI Testing? Check out the [codeless testing documentation](https://testingbot.com/support/web-automate/codeless-automation/add-test) to get started. [View documentation](https://testingbot.com/support/web-automate/codeless-automation/add-test) Resources you may like [![Generative AI test agent](https://testingbot.com/assets/blog/2025/testingbot-ai.webp)](https://testingbot.com/blog/testingbot-ai-agent) #### [Generative AI test agent](https://testingbot.com/blog/testingbot-ai-agent) TestingBot has launched an AI Test Agent that will help you to create automated tests [Read more](https://testingbot.com/blog/testingbot-ai-agent) [![Codeless Web Automation on iOS and Android](https://testingbot.com/assets/blog/2020/seleniumide.webp)](https://testingbot.com/blog/codeless-automation-ios-android) #### [Codeless Web Automation on iOS and Android](https://testingbot.com/blog/codeless-automation-ios-android) We now offer Codeless Automation for websites on iOS Simulators and Android Emulators. [Read more](https://testingbot.com/blog/codeless-automation-ios-android) ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) --- URL: https://testingbot.com/features/accessibility-testing # Web Accessibility Testing TestingBot provides automated accessibility testing to help ensure your web applications comply with WCAG standards and are accessible to all users. Schedule recurring tests, receive detailed reports with actionable insights, and improve your application's accessibility with ease. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Web Accessibility Testing](https://testingbot.com/assets/hero/accessibility_testing-16c85de4dea69c5f2f0c0e421aa1f397623dbc7ec1a7ef3066965e8ad711736e.webp) Trusted by some of the world's most innovative companies ## Automated Accessibility Testing Identify and fix accessibility issues across your websites and web apps. Ensure WCAG compliance and deliver an inclusive experience for all users. ### WCAG Compliance Test your web applications against Web Content Accessibility Guidelines (WCAG) to ensure compliance. ### Scheduled Testing Configure one-time or recurring tests on a daily, weekly, or monthly basis to catch accessibility issues early. ### Detailed Reports Receive comprehensive reports with detailed information about each accessibility violation and recommended fixes. ### Customizable Alerts Set up notifications via email, webhooks, or SMS when accessibility issues are detected. ### Severity Classification Prioritize accessibility issues with clear severity labels to focus on the most critical problems first. ### Secure Testing Test locally hosted and authenticated pages securely using the [TestingBot Tunnel](https://testingbot.com/support/tunnel). ## Accessibility Testing is Essential Make your web applications accessible to all users and comply with regulations. ### Legal Compliance Meet legal requirements, such as the European Accessibility Act (EAA) to avoid any penalties. ### Broader Audience Reach more users by making your applications accessible to people with disabilities, who represent about 15% of the global population. ### Improved SEO Boost your search engine rankings as accessibility improvements often align with SEO best practices. ### Better User Experience Create a better experience for all users by implementing accessibility best practices that often improve usability for everyone. ## Detailed Accessibility Reports Receive comprehensive reports that identify accessibility issues with detailed information about each violation, its severity and recommendations for fixing the issue. [Get started free](https://testingbot.com/users/sign_up) ![Detailed Accessibility Reports](https://testingbot.com/assets/features/accessibility/accessibility_ui-b64827a2253e7d403626e287a9da43bbf597d15b8e61fce56a53d8f3ffb9db1a.jpg) ![WCAG Compliance Testing](https://testingbot.com/assets/features/accessibility/wcag-45f2df574fac1c63f5ef8d3c7d437ba263d4feeff1be18bb950191d751228969.jpg) ## WCAG Compliance Testing Automatically test your web applications against WCAG guidelines to ensure they are accessible to users with disabilities and comply with international standards. [Read more](https://testingbot.com/support/accessibility/web/rules) ## Scheduled Accessibility Tests Configure one-time or recurring accessibility tests on a daily, weekly, or monthly basis to continuously monitor your web applications for accessibility issues. [Read more](https://testingbot.com/support/accessibility/web/scheduled) ![Scheduled Accessibility Tests](https://testingbot.com/assets/features/accessibility/accessibility_alert-aead51f69a0a303862fe064ebb28620f6505bbd2d26bf284c5c1727c82f4a719.jpg) ![WCAG Compliance Testing](https://testingbot.com/assets/features/accessibility/accessibility_code-bdee9af73b2c74be656f5067384af81c2302d810e6a314ed96d9978116e53e9f.jpg) ## Integrate into your existing tests With a few lines of code, you can check for accessibility issues during your automated Selenium tests. No custom SDK, library or framework required. [Read more](https://testingbot.com/support/accessibility/web/selenium) ### Sign up for a Free Trial Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Why is accessibility testing important in web design?](https://testingbot.com/assets/resources/articles/49-ddec8d6d134f657a98d9537849a0bb94fe908d49159be466aa83da15760120a4.webp)](https://testingbot.com/resources/articles/why-accessibility-testing) #### [Why is accessibility testing important in web design?](https://testingbot.com/resources/articles/why-accessibility-testing) Find out why it's important to think about accessibility when designing your webpages. [Read more](https://testingbot.com/resources/articles/why-accessibility-testing) [![Automated Accessibility Testing with TestingBot](https://testingbot.com/assets/blog/2021/accessibility.webp)](https://testingbot.com/blog/automated-accessibility-testing) #### [Automated Accessibility Testing with TestingBot](https://testingbot.com/blog/automated-accessibility-testing) Start testing for accessibility issues with TestingBot and Axe. [Read more](https://testingbot.com/blog/automated-accessibility-testing) --- URL: https://testingbot.com/features/headless # Headless Browsers Connect AI agents and test scripts to remote, headless browsers. Perform automated browser actions, simulate user interactions or perform data-driven tasks with full browser capabilities and zero setup. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Headless Browsers](https://testingbot.com/assets/features/headless/headless-hero-38d22aa0dac3f4e755ca7d810be1172495f2adaa52c25f1a2efa423ca6b74ede.webp) Trusted by some of the world's most innovative companies ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/headless/headless-browsers-39b7c3acbb683809c7f8ae34359638d62c04784315d3435def57f0911013278b.jpg) ## How it works TestingBot takes care of the setup and maintenance of the headless browsers. Run your sessions in parallel on our cloud-based grid, optimized for speed and performance. Take advantage of a high performance platform, with low latency and fast browser startup times. Extract HTML, bypass bot detectors and use user-in-the-loop functionality with Hybrid Automations. [Get started free](https://testingbot.com/users/sign_up) ## Browser Frameworks These automation frameworks support running headless sessions. [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/features/automation/selenium) ### [Selenium](https://testingbot.com/features/automation/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/features/automation/puppeteer) ### [Puppeteer](https://testingbot.com/features/automation/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/features/automation/playwright) ### [Playwright](https://testingbot.com/features/automation/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. ![Instrument native, remote browsers with speed.](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Instrument native, remote browsers with speed. Take advantage of increased performance and speed with headless browsers. Test, scrape or fetch information from websites with real browsers. Feed data to your AI agents. [Get started free](https://testingbot.com/users/sign_up) ## Parallel Sessions Drastically improve your workflow by running sessions simultaneously. TestingBot provides single-use machines on Windows, Linux and macOS, optimized for speed and stability. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ## Video, screenshots & logs Every browser comes with access to generated logs, monitoring, videos and screenshots. [Get started free](https://testingbot.com/users/sign_up) ![Video, screenshots & logs](https://testingbot.com/assets/features/app-automated-report-dcef51604982dffa3ee9f02b87a92cef82132f9e21c5b66683738ab69f634ecf.jpg) ![WCAG Compliance Testing](https://testingbot.com/assets/features/headless/headless-scripts-dab9e6afb5d1bc095e14efd5f2054cfb36b50c5dea0be0ec20a9120f21097703.webp) ## Remote Browser Functions Use TestingBot Functions to easily scrape URLs, automate actions, generate PDFs/screenshots and more. [Read more](https://testingbot.com/support/functions) ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart for Playwright](https://testingbot.com/support/web-automate/playwright) - [Run Puppeteer on TestingBot](https://testingbot.com/support/web-automate/puppeteer) - [Functions: scrape, take screenshots and serverless functions](https://testingbot.com/support/functions) - [Playwright Recorder](https://testingbot.com/support/web-automate/playwright/recorder) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start your first headless browser session? Please see the [Playwright documentation](https://testingbot.com/support/web-automate/playwright) to get started. [View documentation](https://testingbot.com/support/web-automate/playwright) Resources you may like [![Automated Testing with Puppeteer](https://testingbot.com/assets/resources/articles/11-416015eb394d928299663409dccd67993b0a664f4b3ff456803fefc6bf1f325a.webp)](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) #### [Automated Testing with Puppeteer](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) Puppeteer combined with a test framework provides a great way to run automated browser tests. Follow this guide for more information. [Read more](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) [![Visual Testing with Playwright](https://testingbot.com/assets/resources/articles/14-f3f2e8954c8a47cf0bb29059b44f4d2f40998442e22db6f8acdccb8e5b34d8c1.webp)](https://testingbot.com/resources/articles/playwright-visual-regression-testing) #### [Visual Testing with Playwright](https://testingbot.com/resources/articles/playwright-visual-regression-testing) Playwright provides automated browser testing. It offers a built-in feature to perform visual regression testing for your website. [Read more](https://testingbot.com/resources/articles/playwright-visual-regression-testing) [![Puppeteer Testing in the Cloud](https://testingbot.com/assets/blog/2021/puppeteer.webp)](https://testingbot.com/blog/puppeteer-cloud-testing) #### [Puppeteer Testing in the Cloud](https://testingbot.com/blog/puppeteer-cloud-testing) Start running Puppeteer tests in the cloud with TestingBot. [Read more](https://testingbot.com/blog/puppeteer-cloud-testing) --- URL: https://testingbot.com/features/screenshot-testing # Automated Visual UI Regression Testing Detect and fix visual issues on your webpages and mobile apps before they impact users. Leverage TestingBot's codeless visual UI testing to get instant alerts whenever a visual discrepancy is detected on your site. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Automated Visual UI Regression Testing](https://testingbot.com/assets/hero/visual-abbead5878a5c7c5d80577279ba1f4c14a31df4ffdb0309dad7f6b7c3b09e63e.svg) Trusted by some of the world's most innovative companies ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/screenshot-command-8a1297c081a302dc4dbc77a4e4461dec802ee7f7cfc8153948e2e06ee30b891e.jpg) ## Effortless Visual Regression Testing Enable visual regression testing in your existing test framework with a single line of code. Quickly detect layout shifts, UI inconsistencies and visual regressions during your test. Or enter the URLs you would like to monitor. TestingBot will take screenshots on regular intervals and alert you when a change is detected. [Get started free](https://testingbot.com/users/sign_up) ## Review and Approve Visual Regressions You and your team can review visual test results, approving or rejecting specific UI changes. Use a slider to compare the baseline and new screenshots or analyze a diff image highlighting the differences. ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/visual_schedule-8bc03556f3225d26b8fd4e5bdb31c1881ef2abb3257c35093cc441b5b62abbaa.jpg) ## Codeless Visual UI Testing Start identifying UI defects on your website in minutes. Just enter your URL, select the browsers you want to test on, and set the testing frequency. Customize alerts to get notified instantly when issues are detected. When a visual change occurs, you'll receive an instant alert with a screenshot and a diff image highlighting the differences. Keep your UI and UX flawless by catching unexpected changes early. [Get started free](https://testingbot.com/users/sign_up) ## Optimized for accuracy We built visual testing with accuracy in mind, preventing false-positives during the UI verification process. ### Freeze animations and videos Animations and videos are temporarily frozen during the visual snapshot, to prevent false positives. ### Ignore UI elements We ignore certain UI elements that are prone to change and are irrelevant to the screenshot. ### Pixel Perfect Screenshots Take full-page, above the fold or chromeless screenshots of your website across hundreds of browsers and devices at once. ## Test Automation Frameworks TestingBot's UI testing seamlessly integrates with Selenium, Appium, Puppeteer and Playwright. Just add a single line of code to enhance your existing tests with automated visual regression testing. [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/support/visual-testing/automated/selenium) ### [Selenium](https://testingbot.com/support/visual-testing/automated/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/support/visual-testing/automated/appium) ### [Appium](https://testingbot.com/support/visual-testing/automated/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/support/visual-testing/automated/playwright) ### [Playwright](https://testingbot.com/support/visual-testing/automated/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/support/visual-testing/automated/puppeteer) ### [Puppeteer](https://testingbot.com/support/visual-testing/automated/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. ## Frequently Asked Questions ### How can I use this to spot visual defects? TestingBot performs automated pixel-by-pixel comparisons between an image that you marked as correct and a new screenshot that was just taken. If the amount of different pixels exceeds the threshold, the test is considered as failed. This can happen when you deploy a new version of your website that has an incorrect CSS styling, positioning or is missing from the page. Catch visual bugs before these cause harm to the UX of your webpages. ### Why can’t functional tests cover visual problems? You can test for dimensions, positioning and styling with regular functional tests. The disadvantage is that it will soon become a huge burden of checkpoints in your code. Instead of doing the visual checks in your code, it is much more efficient to take snapshots and compare these. The visual results are also much more easily interpreted by developers and QA. ### When Should I Use Visual Testing? Ideally you would run visual checks as part of your CI/CD pipeline. It could be run after each check-in of front-end code, making sure new code does not negatively impact your product. ### Can AI be used for visual testing? Machine learning algorithms can be trained to discover visual differences. AI depends on trained data, so it may report false positives/negatives. It is not a Not a One-Size-Fits-All solution and often fails in comparison with exact pixel matching. ### How does Snapshot Testing work? Snapshot Testing in the context of visual testing for UI on webpages, captures screenshots of the initial state of a webpage. It then compares them against subsequent renders. Tests are considered failed when one or more changes in visual appearance occur. This helps to ensure that UI elements remain consistent. ### Sign up for a Free Trial Start visually testing your apps and websites with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Visual Regression Testing with Python](https://testingbot.com/assets/resources/articles/20-823a333072d87c93f6d75a502e3073e32bd0bee1d3142540ce0b42da6fa7ccf0.webp)](https://testingbot.com/resources/articles/python-visual-testing) #### [Visual Regression Testing with Python](https://testingbot.com/resources/articles/python-visual-testing) Find out how to do automated visual UI testing with the power of Python and TestingBot. [Read more](https://testingbot.com/resources/articles/python-visual-testing) [![Angular UI Testing](https://testingbot.com/assets/resources/articles/21-15af461a46c449ef26dfb952ed9d0fc327c97d9ca815f24f8fe9ee60b9aa64a5.webp)](https://testingbot.com/resources/articles/angular-ui-testing) #### [Angular UI Testing](https://testingbot.com/resources/articles/angular-ui-testing) Learn more about using Visual UI Testing in combination with Cypress to test Angular UI apps. [Read more](https://testingbot.com/resources/articles/angular-ui-testing) [![Visual Regression Testing](https://testingbot.com/assets/blog/2024/visual-testing.webp)](https://testingbot.com/blog/visual-regression-testing) #### [Visual Regression Testing](https://testingbot.com/blog/visual-regression-testing) Learn about TestingBot's visual testing feature, allowing you to easily compare layouts across browsers and devices. [Read more](https://testingbot.com/blog/visual-regression-testing) --- URL: https://testingbot.com/features/automation/puppeteer # Puppeteer Cloud Automation Connect your Puppeteer scripts to TestingBot's cloud-based browser grid. Run Puppeteer tests on Chrome and Edge across multiple operating systems for seamless cross-browser automation. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Puppeteer Cloud Automation](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg) Trusted by some of the world's most innovative companies Platform Features ## Online Puppeteer Browser Grid Connect your Puppeteer scripts with an online browser grid, consisting of over **50 different browser, OS and version combinations**. Run tests in headless or headful mode. Easily scale from 1 to +100 simultaneous sessions with Puppeteer. ### Parallel Testing Run multiple Puppeteer tests simultaneously, shortening your total Puppeteer execution time. ### Test artifacts Every test on TestingBot includes a video screencast of the device, along with logs and other generated artifacts. ### TestingBot Tunnel Run Puppeteer tests against websites in a secure environment such as a private network, staging environment or local machine. ### Geolocation Testing Run Puppeteer tests with TestingBot's built-in geo-location testing feature. Choose from up to 20 regions around the globe. Fast Execution ## Parallel Testing Run multiple Puppeteer tests simultaneously, shortening your total Puppeteer execution time. [Get started free](https://testingbot.com/users/sign_up) ![Reduce Test Execution Time](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Framework Support ## Test Framework Integrations TestingBot integrates with Puppeteer and popular test frameworks supporting Puppeteer, such as: - [Jest](https://testingbot.com/support/web-automate/puppeteer/jest) - [WebdriverIO](https://testingbot.com/support/web-automate/puppeteer/webdriverio) - [PyTest](https://testingbot.com/support/web-automate/puppeteer/pytest) Record Puppeteer scripts with the [Puppeteer Recorder](https://testingbot.com/support/web-automate/puppeteer/recorder). Run the recorded Puppeteer scripts on TestingBot's browser grid for maximum coverage. ![Test Framework Integrations](https://testingbot.com/assets/features/puppeteer/puppeteer-frameworks-6bcbf79c5f61ab3b8a2e90898024f19271ff3eff9755baed210c420cf0dc186f.png) Continuous Integration ## Integrations with CI/CD services TestingBot integrates with the most popular CI/CD services, including Jenkins, Bamboo, TeamCity, Circle CI, GitLab CI and more. [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub Actions](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ## Frequently Asked Questions ### Is Selenium better than Puppeteer? Selenium and Puppeteer are both powerful browser automation tools, but they serve different needs. Puppeteer is a NodeJS library that provides fast, high-level control over Chrome and Chromium, making it a great choice for projects focused on headless browser testing or web scraping with JavaScript. It is known for its speed and reliability when testing in a Chromium-only environment. Selenium, on the other hand, is a cross-browser testing framework that supports all major browsers, including Chrome, Firefox, Safari, Edge, and Internet Explorer. It allows you to write tests in multiple programming languages such as Java, Python, C#, Ruby and JavaScript, offering greater flexibility for diverse teams. If your goal is to test across different browsers and environments, Selenium offers broader test coverage and long-standing industry support. If your project is JavaScript-based and you only need to test in Chrome/Chromium, Puppeteer might be faster and easier to set up. At TestingBot, we support both Selenium and Puppeteer, allowing you to choose the best tool for your specific testing needs. ### What is Puppeteer Testing? Puppeteer testing refers to using Puppeteer, a NodeJS library developed by Google, to automate browser tasks for web application testing. Puppeteer provides a high-level API to control Chrome or Chromium browsers, allowing developers and QA teams to script actions like clicking buttons, filling forms, taking screenshots and generating PDFs. ### How do I run Puppeteer tests in the cloud? You can run Puppeteer tests in the cloud using a service like TestingBot. Instead of running tests locally, you upload your tests or point your script to TestingBot’s cloud grid, which spins up real browsers and devices. This allows you to scale tests across multiple environments and get faster results, without managing your own infrastructure. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Puppeteer Testing documentation](https://testingbot.com/support/web-automate/puppeteer) - [Puppeteer Recorder](https://testingbot.com/support/web-automate/puppeteer/recorder) - [CI/CD integration](https://testingbot.com/support/integrations/ci-cd) - [Puppeteer & WebdriverIO](https://testingbot.com/support/web-automate/puppeteer/webdriverio) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Puppeteer Testing? To get started, please see our [Puppeteer Testing](https://testingbot.com/support/web-automate/puppeteer) documentation. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Automated Testing with Puppeteer](https://testingbot.com/assets/resources/articles/11-416015eb394d928299663409dccd67993b0a664f4b3ff456803fefc6bf1f325a.webp)](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) #### [Automated Testing with Puppeteer](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) Puppeteer combined with a test framework provides a great way to run automated browser tests. Follow this guide for more information. [Read more](https://testingbot.com/resources/articles/automated-testing-with-puppeteer) [![Puppeteer Testing in the Cloud](https://testingbot.com/assets/blog/2021/puppeteer.webp)](https://testingbot.com/blog/puppeteer-cloud-testing) #### [Puppeteer Testing in the Cloud](https://testingbot.com/blog/puppeteer-cloud-testing) Start running Puppeteer tests in the cloud with TestingBot. [Read more](https://testingbot.com/blog/puppeteer-cloud-testing) --- URL: https://testingbot.com/features/automation/playwright # Playwright Cloud Automation Connect your Playwright scripts to a cloud-based browser grid and run tests across multiple browsers and operating systems. Scale your testing effortlessly with real browser environments. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Playwright Cloud Automation](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg) Trusted by some of the world's most innovative companies Platform Features ## Extensive Online Browser Grid Connect your Playwright scripts with an online browser grid, consisting of over **100 different browser, OS and version combinations**. Run tests in headless or headful mode. Easily scale from 1 to +100 simultaneous tests with Playwright. ### Parallel Testing Run Playwright tests at scale with a cloud-based grid. Drastically shorten your total Playwright execution time with TestingBot. ### Test artifacts Every test on TestingBot includes a video screencast of the device, along with logs and other generated artifacts. ### TestingBot Tunnel Run Playwright tests against websites in a secure environment such as a private network, staging environment or local machine. ### Geolocation Testing Run Playwright tests with TestingBot's built-in geo-location testing feature. Choose from up to 20 regions around the globe. Fast Execution ## Parallel Testing Run Playwright tests at scale with a cloud-based grid. Drastically shorten your total Playwright execution time with TestingBot. [Get started free](https://testingbot.com/users/sign_up) ![Reduce Test Execution Time](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Framework Support ## Test Framework Integrations Integrate TestingBot with Playwright and popular test frameworks, such as: - [Jest](https://testingbot.com/support/web-automate/playwright/jest) - [Mocha](https://testingbot.com/support/web-automate/playwright/mocha) - [PyTest](https://testingbot.com/support/web-automate/playwright/pytest) - [Playwright Test](https://testingbot.com/support/web-automate/playwright/playwright-test) Use the [Playwright Recorder](https://testingbot.com/support/web-automate/playwright/recorder) to generate Playwright scripts without writing code. Run the recorded tests on the TestingBot browser grid. ![Test Framework Integrations](https://testingbot.com/assets/features/playwright/playwright-frameworks-2e6010df4fa974fb54c8ec5532fc6c5a91933af27884ec04d51c92dab418fe86.png) Continuous Integration ## Integrations with CI/CD services TestingBot integrates with the most popular CI/CD services, including Jenkins, Bamboo, TeamCity, Circle CI, GitLab CI and more. [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub Actions](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) Why TestingBot ## TestingBot vs Microsoft Playwright Testing (MPT) While Microsoft offers its own cloud-based Playwright testing service—Microsoft Playwright Testing (MPT)—there are several key advantages to using TestingBot: ### Predictable pricing TestingBot provides plans with unlimited test minutes, unlike MPT which charges per minute and even adds separate charges for reporting. ### Cross-platform support TestingBot allows Playwright testing on Windows, Linux, and macOS. MPT currently supports only Windows and Linux. ### Real browser testing TestingBot uses real Chrome browsers, while MPT uses Chromium. With Chromium, you're not testing on the exact browsers your users are using. ### Trusted experience TestingBot has been providing reliable automated testing since 2012. MPT is a newer, smaller feature within the Microsoft ecosystem. ### Test behind firewalls TestingBot supports local testing via the TestingBot Tunnel, allowing secure testing of private or staging environments. MPT does not offer this feature. ## Frequently Asked Questions ### How does Playwright differ from Puppeteer? Both Playwright and Puppeteer are browser automation tools, but Playwright offers native support for all major browsers (Chrome, Firefox, Safari, Edge), while Puppeteer mainly focuses on Chrome and Chromium. Playwright also provides features like network interception, multi-page/tab support, and out-of-the-box mobile emulation, making it more flexible for complex testing scenarios. ### Can Playwright run tests on real devices? By default, Playwright supports device emulation, which mimics the behavior of mobile devices. TestingBot supports [running Playwright tests on real Android devices](https://testingbot.com/support/web-automate/playwright/mobile). ### How do I integrate Playwright with CI/CD? Playwright works seamlessly with popular CI/CD systems such as GitHub Actions, GitLab CI, Jenkins, CircleCI, Travis CI and Bitbucket Pipelines. TestingBot provides ready-made examples and integrations to help you easily connect Playwright with your build pipeline and run tests automatically on every push or pull request. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Playwright Testing documentation](https://testingbot.com/support/web-automate/playwright) - [Playwright Recorder](https://testingbot.com/support/web-automate/playwright/recorder) - [Visual regression testing with Playwright](https://testingbot.com/support/web-automate/playwright/visual-regression-testing) - [Mobile Playwright Testing](https://testingbot.com/support/web-automate/playwright/mobile) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) Resources you may like [![Visual Testing with Playwright](https://testingbot.com/assets/resources/articles/14-f3f2e8954c8a47cf0bb29059b44f4d2f40998442e22db6f8acdccb8e5b34d8c1.webp)](https://testingbot.com/resources/articles/playwright-visual-regression-testing) #### [Visual Testing with Playwright](https://testingbot.com/resources/articles/playwright-visual-regression-testing) Playwright provides automated browser testing. It offers a built-in feature to perform visual regression testing for your website. [Read more](https://testingbot.com/resources/articles/playwright-visual-regression-testing) [![Record tests with Playwright](https://testingbot.com/assets/resources/articles/32-277318b88c5e35eb2c96f03d9b53a1ef8eb2d96db184679892b5008b0bad9d0f.webp)](https://testingbot.com/resources/articles/playwright-recorder) #### [Record tests with Playwright](https://testingbot.com/resources/articles/playwright-recorder) Learn how to use a Playwright Recorder to easily record tests. [Read more](https://testingbot.com/resources/articles/playwright-recorder) ### Ready to start Playwright Testing? Please see our [Playwright Testing](https://testingbot.com/support/web-automate/playwright) documentation on how to get started. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/automation/selenium # Selenium Cloud Automation Supercharge your Selenium Test Automation with a cloud-based browser and device grid, enabling faster, scalable testing across multiple browsers and devices simultaneously. Connect your Selenium tests with a browser grid of +5200 desktop and mobile browsers. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Selenium Cloud Automation](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg) Trusted by some of the world's most innovative companies ![Test Results](https://testingbot.com/assets/features/test-results-315382c39a67ad52167d2a4fd78570c99aea3e0ec386c17e82265851e93cb7b3.png) Test Results ## Test Results Every Selenium test result includes screenshots, logs, and videos. Easily track test status, access artifacts via REST API, and integrate with your existing tools for seamless reporting and analysis. Customize Selenium sessions by specifying various options, including: - All Selenium versions supported - Custom Screen Resolution - Custom Timezone - Change Geolocation - Browser startup flags and [more](https://testingbot.com/support/web-automate/selenium/test-options) Framework Support ## Selenium Integrations TestingBot integrates with various test frameworks and services. Easily convert your existing Selenium tests and connect with your favorite CI/CD. ### [C#](https://testingbot.com/support/web-automate/selenium/csharp) - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) ### [NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs) - [NightWatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) - [TestCafe](https://testingbot.com/support/web-automate/selenium/nodejs/testcafe) ### [Java](https://testingbot.com/support/web-automate/selenium/java) - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) - [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide) ### [PHP](https://testingbot.com/support/web-automate/selenium/php) - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) ### [Python](https://testingbot.com/support/web-automate/selenium/python) - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) ### [Ruby](https://testingbot.com/support/web-automate/selenium/ruby) - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Location Features ## Geolocation Testing Perform **geolocation testing** in various regions across the world. Test Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. Secure Infrastructure ## Accurate Testing Run your tests in a secure datacenter on real operating systems. Each test runs in an isolated, single-use VM, ensuring high performance and minimal flakiness. VMs are automatically destroyed after each test for maximum security and reliability. Our infrastructure is optimized for performance and low test flakiness. [Get started free](https://testingbot.com/users/sign_up) Fast Execution ## Parallel Testing Drastically shorten your total Selenium test duration by running tests simultaneously. TestingBot provides single-use VMs on Windows, Linux and macOS, optimized for speed and stability. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Continuous Integration ## Integrations with CI/CD services TestingBot integrates with the most popular CI/CD services, including Jenkins, Bamboo, TeamCity, Circle CI, GitLab CI and more. [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) Device Cloud ## Mobile Testing Test on physical iOS and Android mobile devices, or iOS simulators and Android emulators. Test your website functionality and UI on various mobile devices and versions, with geolocation support. [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-abb9a661ebbfa84f18bd6985d3e80330ad43fe4ea7d408157c87ae0f560a5ca1.webp) Pixel 9 ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-ba3caa0fe8fb834ea684e524f6ad690ca4f78402e85a51a48e94ad4dfcb93208.webp) Galaxy S25 ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Test Staged Websites Use the secure TestingBot Tunnel to easily test your staging and development environments across all browsers, ensuring seamless access behind firewalls or private networks. Test data and websites from behind your firewall on the TestingBot cloud. [Read more](https://testingbot.com/support/tunnel) ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Selenium Quickstart Documentation](https://testingbot.com/support/web-automate/selenium) - [Selenium 4](https://testingbot.com/support/web-automate/selenium/selenium4) - [CI/CD integration](https://testingbot.com/support/integrations/ci-cd) - [Selenium BiDi](https://testingbot.com/support/web-automate/selenium/selenium-bidi) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to accelerate your Selenium Testing? Please see our [Selenium Testing](https://testingbot.com/support/web-automate/selenium) documentation on how to get started. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Selenium and Generative AI](https://testingbot.com/assets/resources/articles/28-af707bf052844eb00f861bb6ebba57e6be4479dde1c78a5df4e70d2f597a8b18.webp)](https://testingbot.com/resources/articles/generative-ai-selenium) #### [Selenium and Generative AI](https://testingbot.com/resources/articles/generative-ai-selenium) Generate realistic looking test data to be used with your Selenium Automated Tests. [Read more](https://testingbot.com/resources/articles/generative-ai-selenium) [![Selenium 4: what's new](https://testingbot.com/assets/blog/2021/se4.webp)](https://testingbot.com/blog/selenium-4) #### [Selenium 4: what's new](https://testingbot.com/blog/selenium-4) Learn more about what is new Selenium 4. [Read more](https://testingbot.com/blog/selenium-4) [![Selenium WebDriver BiDi](https://testingbot.com/assets/blog/2024/bidi.webp)](https://testingbot.com/blog/webdriver-bidi) #### [Selenium WebDriver BiDi](https://testingbot.com/blog/webdriver-bidi) WebDriver BiDi support is now available on TestingBot. Learn how to use this exciting new improvement with your Selenium tests. [Read more](https://testingbot.com/blog/webdriver-bidi) --- URL: https://testingbot.com/features/automation/cypress # Cypress Cloud Automation Scale your Cypress Tests with TestingBot. Functional and cross browser testing with Cypress on +40 browsers in the cloud. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Cypress Cloud Automation](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg) Trusted by some of the world's most innovative companies Cross-Browser Testing ## Cross-Browser testing with Cypress Run Cypress tests on +40 browsers in the cloud. TestingBot provides Windows and macOS testing for Cypress on multiple browser versions. ![chrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Chrome") ### Google Chrome 66 & above ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") ### Mozilla Firefox 60 & above ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") ### Microsoft Edge 80 & above Getting Started ## How does it work? Get started with Cypress cloud testing in three simple steps 1 ### Install the Runner Install the TestingBot Cypress CLI to trigger tests and receive test results. $ npm i testingbot-cypress-cli 2 ### Configure the Runner Configure the JSON file to specify the location of your Cypress test files and other additional options. [Learn more](https://testingbot.com/support/web-automate/cypress#configure) 3 ### Run Cypress Tests Trigger the tests via the CLI runner. Your Cypress tests will run in parallel and appear in the TestingBot dashboard, with logs and a video. Global Testing ## Geolocation Testing Perform **geolocation testing** in various regions across the world. Test Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. ![Test Results](https://testingbot.com/assets/features/test-results-315382c39a67ad52167d2a4fd78570c99aea3e0ec386c17e82265851e93cb7b3.png) Test Artifacts ## Test Results Every Cypress test result includes screenshots, logs, and videos. Easily track test status, access artifacts via REST API, and integrate with your existing tools for seamless reporting and analysis. Customize Cypress sessions by specifying various options, including: - Various [Cypress versions](https://testingbot.com/support/web-automate/cypress/version) supported - Custom Screen Resolution - Custom Timezone - Change Geolocation Fast Execution ## Parallel Testing with Cypress Speed up your release cycles with Cypress Parallel Testing on TestingBot's Cloud. Run Cypress tests in parallel on multiple browsers, versions and operating systems. 10x Faster Testing 100+ Concurrent Tests [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing with Cypress](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ## Frequently Asked Questions ### What is the advantage of running Cypress in the Cloud? TestingBot provides, and maintains, the infrastructure to run Cypress tests in parallel on multiple browsers, versions and operating systems. You no longer need to maintain, patch and upgrade virtual machines or docker images. TestingBot offers high-scale parallelization with easy integration in your CI/CD pipeline. All Cypress tests come with debug logs, screenshots and video. ### Is it possible to integrate Cypress testing in my CI/CD pipeline? Starting Cypress tests from your CI/CD is very similar to how you would run the tests from your local machine. Install the TestingBot-Cypress CLI, provide the necessary configuration and your CI/CD server can run Cypress tests on TestingBot. The built-in JUnit reporter in the TestingBot-Cypress CLI can show success and failure from inside your CI/CD pipeline. ### Can I run Cypress tests on multiple browsers? TestingBot allows you to run Cypress tests on multiple browsers, including 40+ versions of Chrome, Edge and Firefox on Windows and macOS. Specify the browser, version and OS in the testingbot.json file and start your tests. ### Where can I see the Cypress test results? The Cypress test results will appear in realtime through the TestingBot-Cypress CLI. When the tests have finished, you can see the Cypress test results in the TestingBot dashboard, together with screenshots, logs and a video. Resources you may like [![Tutorial on debugging Cypress tests](https://testingbot.com/assets/resources/articles/10-7ae9f6d9435bea1c54ec815ad535dc4a590086e6165263a9eba3441635d55726.webp)](https://testingbot.com/resources/articles/how-to-debug-cypress-tests) #### [Tutorial on debugging Cypress tests](https://testingbot.com/resources/articles/how-to-debug-cypress-tests) This article will focus on how to debug your Cypress tests with Cypress debugger and other developer tools. [Read more](https://testingbot.com/resources/articles/how-to-debug-cypress-tests) [![Cypress and Cucumber Browser Testing](https://testingbot.com/assets/resources/articles/6-495c5e14cb4bf1e282858fc7e2cfcbe89775e3790b88d34c15bf9a6f36d387d4.webp)](https://testingbot.com/resources/articles/cypress-cucumber-testing) #### [Cypress and Cucumber Browser Testing](https://testingbot.com/resources/articles/cypress-cucumber-testing) Cypress and Cucumber is a great combination to write clean and precise end-to-end browser tests. [Read more](https://testingbot.com/resources/articles/cypress-cucumber-testing) [![Run Cypress tests on TestingBot's Browser Grid](https://testingbot.com/assets/blog/2020/cypress.webp)](https://testingbot.com/blog/testingbot-cypress) #### [Run Cypress tests on TestingBot's Browser Grid](https://testingbot.com/blog/testingbot-cypress) Run Cypress Automated tests on TestingBot's Browser grid. [Read more](https://testingbot.com/blog/testingbot-cypress) ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Cypress Cloud Testing](https://testingbot.com/support/web-automate/cypress) - [Cypress DevTools Recorder](https://testingbot.com/support/web-automate/cypress/devtools) - [CI/CD integration setup guides](https://testingbot.com/support/integrations) - [List of browsers for Cypress](https://testingbot.com/support/web-automate/cypress/capabilities) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Cypress Testing? To get started, please see our [Cypress Testing](https://testingbot.com/support/web-automate/cypress) documentation. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/automation/espresso # Android Espresso Automation Scale your Espresso Tests with TestingBot. Run Espresso tests for your native and hybrid apps across physical Android devices and Android emulators. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Android Espresso Automation](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg) Trusted by some of the world's most innovative companies ## How does it work? 1 ### Build your app & tests Create an .apk or .aab file of your native Android app, and a .apk file of your Espresso tests. You can use Android Studio or Gradle to create these files, in either Java or Kotlin. 2 ### Upload app and tests Upload your mobile app (.apk or .aab) and tests (.apk) via the TestingBot REST API. [Learn more](https://testingbot.com/support/app-automate/espresso#upload) 3 ### Run Espresso Tests Trigger the tests via an API call. Your tests will appear in the TestingBot dashboard, with video, logs and more. Fast Execution ## Parallel Testing with Espresso Speed up your release cycles with Parallel Testing on Espresso Real Android Devices. Upload multiple apps and execute tests simultaneously for quicker, more efficient results. [Get started free](https://testingbot.com/users/sign_up) ![Reduce Test Execution Time](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Java & Kotlin ## Test Android apps with Java and Kotlin Test your Android apps with Java and Kotlin on real devices with cloud-based Espresso automation. ![Test Android apps with Java and Kotlin](https://testingbot.com/assets/features/espresso/espresso-da63a108b0e887eae34ac39de7d5df9a3e4aa37423986d787f044bdf1339248c.png) Device Cloud ## Espresso Real Device Cloud Test on real Android devices on the TestingBot cloud platform with Espresso. TestingBot provides devices from Android 4.4 up to Android 15. [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-abb9a661ebbfa84f18bd6985d3e80330ad43fe4ea7d408157c87ae0f560a5ca1.webp) Pixel 9 ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-ba3caa0fe8fb834ea684e524f6ad690ca4f78402e85a51a48e94ad4dfcb93208.webp) Galaxy S25 ![Test online on Redmi Note 13](https://testingbot.com/assets/devices/160h/32-5f416c0f9e99cc3c6782b2b50072f406a8056e009850c16693dbc1fe815f88db.webp) Redmi Note 13 ![Test online on Galaxy A55](https://testingbot.com/assets/devices/160h/30-ee1932ef83ba5feee5414d6eb777943fb0ba2c6250a83a966761ae70e2bfb4c2.webp) Galaxy A55 Continuous Integration ## CI/CD Integration Integrate TestingBot Espresso Testing with your CI/CD [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) Enterprise ## Private Device Cloud With Private Device Cloud, we take care of the setup, configuration and maintenance of dedicated devices exclusively for your company. Select your preferred devices, and we will make them available in our data center for seamless testing. [Learn more](https://testingbot.com/enterprise/private-device-cloud) ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 Private Device ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 Private Device ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-abb9a661ebbfa84f18bd6985d3e80330ad43fe4ea7d408157c87ae0f560a5ca1.webp) Pixel 9 Private Device ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-ba3caa0fe8fb834ea684e524f6ad690ca4f78402e85a51a48e94ad4dfcb93208.webp) Galaxy S25 Private Device ![Test online on Redmi Note 13](https://testingbot.com/assets/devices/160h/32-5f416c0f9e99cc3c6782b2b50072f406a8056e009850c16693dbc1fe815f88db.webp) Redmi Note 13 Private Device ![Test online on Galaxy A55](https://testingbot.com/assets/devices/160h/30-ee1932ef83ba5feee5414d6eb777943fb0ba2c6250a83a966761ae70e2bfb4c2.webp) Galaxy A55 Private Device ## Frequently Asked Questions ### What is the advantage of running Android Espresso tests in the Cloud? By running Android Espresso tests on TestingBot, you can run tests in parallel on multiple devices and emulators at once. Running tests in parallel will drastically shorten the total test duration. TestingBot offers a variety of Android devices, including Samsung, Pixel, Oppo and other brands. ### Is it possible to integrate Android Espresso testing in my CI/CD pipeline? You can easily add the upload step and run step in your CI/CD pipeline. As part of your CI/CD, you can then run the Android Espresso tests on TestingBot. Use the JUnit report XML functionality that TestingBot provides to integrate the test results in your CI/CD. ### What other options are available during Espresso testing? You can change the network speed, language and locale of the device, change the GeoIP location and more. The Espresso filters are all available, so you can choose which tests you want to run. ### Where can I see the Espresso test results? The Espresso test results will appear in the TestingBot dashboard. You can use the REST API as well to fetch the results. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Espresso Cloud Testing](https://testingbot.com/support/app-automate/espresso) - [Localization testing with Espresso](https://testingbot.com/support/app-automate/espresso/set-localization-options) - [CI/CD integration setup guides](https://testingbot.com/support/integrations/ci-cd) - [Taking screenshots with Espresso](https://testingbot.com/support/app-automate/espresso/screenshots) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Espresso Testing? To get started, please see our [Espresso Testing](https://testingbot.com/support/app-automate/espresso) documentation. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Android Espresso Tutorial](https://testingbot.com/assets/resources/articles/19-fe4971eb8049097c25f2cc2fce95b71b94f3bb342e094c219b2404c09374f015.webp)](https://testingbot.com/resources/articles/android-espresso-testing) #### [Android Espresso Tutorial](https://testingbot.com/resources/articles/android-espresso-testing) Learn more about Android Espresso Testing in this tutorial. [Read more](https://testingbot.com/resources/articles/android-espresso-testing) --- URL: https://testingbot.com/features/automation/maestro # Maestro Cloud Testing Run Maestro Tests twice as fast with TestingBot at ⅓ the cost. iOS simulators, Android emulators and real devices with zero setup. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) https://www.youtube.com/embed/MMWCkBgXFOU Trusted by some of the world's most innovative companies ## Drop-in Replacement for Maestro Cloud Switch from Maestro Cloud CLI to TestingBot in seconds. Simply replace `maestro cloud` with `testingbot maestro` Android Flow Example -`maestro cloud android.apk flow.yaml` +`testingbot maestro android.apk flow.yaml` ### Quick Start $ npm install -g testingbot-cli $ testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" ### Advanced Options $ testingbot maestro app.apk ./flows \ -e API_URL=https://staging.example.com $ testingbot maestro app.apk ./flows \ --include-tags "smoke,critical" ### CLI Options | Option | Description | | --- | --- | | --device | Device name (e.g., "Pixel 8", "iPhone 15") | | --real-device | Target a physical device (iOS or Android) | | --deviceVersion | OS version (e.g., "14" for Android, "17.0" for iOS) | | --maestro-version | Specify Maestro version (e.g., "2.0.10") | | -e, --env | Pass environment variables to your tests | | --include-tags | Run only flows with specified tags | | --exclude-tags | Skip flows with specified tags | | --name | Custom name for your test run | | --locale | Set device locale (e.g., "de\_DE", "fr\_FR") | [View all CLI options](https://testingbot.com/support/app-automate/maestro/options) [Get Started Free](https://testingbot.com/users/sign_up) ## How can I perform Maestro Cloud Testing? 1 ### Upload your mobile app Upload your mobile app (.apk, .aab or .zip) through CLI, or via the TestingBot REST API. 2 ### Upload Maestro Flows Upload your Maestro test flows. [Learn more](https://testingbot.com/support/app-automate/maestro) 3 ### Run Maestro Tests Run your Maestro flows in parallel. Flows appear in the TestingBot dashboard with steps, screenshots and video recordings. ## TestingBot vs Other Maestro Cloud Providers See why TestingBot is the better choice for your Maestro testing needs | Feature | TestingBot ✨ Winner | Maestro Cloud | DeviceCloud | | --- | --- | --- | --- | | 💰 Pricing | 1/3 the cost | 3x more expensive | Pay per test run | | 📱 Real Physical Devices (iOS and Android) | | | | | 📲 iPhone/iPad Simulators | | | Pay extra for specific iOS versions and devices | | 🤖 Android Emulators with Google Play APIs | Full support | Limited | Pay extra | | 💳 In-App Purchase Testing | Available on Android | | | | 🔄 Portrait/Landscape Mode | Full control | Basic | | | 🌍 Geolocation Testing | Any location | | | | 🌐 Device Locale Testing | 20+ locales | Limited | 9 locales | | 📹 Real-time Video Streaming | Live streaming | Post-test only | Live streaming | | 📊 Real-time Logs | Live streaming | Basic | Live streaming | | ⚡ Performance | 2x faster (Mac Silicon + ARM performance) | Standard speed | Standard speed | [Start Testing with TestingBot](https://testingbot.com/users/sign_up) [Request a demo](https://testingbot.com/demo) or [view pricing](https://testingbot.com/pricing) Fast Execution ## Parallel Testing Run multiple Maestro flows simultaneously across different sessions and devices. Scale your testing with parallel execution for faster feedback. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Real-time Insights ## Real Time Console View your Maestro test results in real time with detailed logs and insights. Or use the API to fetch your test results. [Get started free](https://testingbot.com/users/sign_up) ![Maestro results](https://testingbot.com/assets/support/maestro/results-78a1591a85866ec01fa9a661652d9fd4cf0b24989743d73756e8a991157dd7be.png) Location Features ## Geolocation Testing Test your app's location-based features by simulating different geographic locations. Verify location-specific content and functionality. Device Cloud ## Maestro Device Cloud Test on physical iOS and Android devices + iOS Simulators and Android emulators. Run tests on iOS 16 up to 26. Android 10 up to 16. [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-abb9a661ebbfa84f18bd6985d3e80330ad43fe4ea7d408157c87ae0f560a5ca1.webp) Pixel 9 ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-ba3caa0fe8fb834ea684e524f6ad690ca4f78402e85a51a48e94ad4dfcb93208.webp) Galaxy S25 ![Test online on Redmi Note 13](https://testingbot.com/assets/devices/160h/32-5f416c0f9e99cc3c6782b2b50072f406a8056e009850c16693dbc1fe815f88db.webp) Redmi Note 13 ![Test online on Galaxy A55](https://testingbot.com/assets/devices/160h/30-ee1932ef83ba5feee5414d6eb777943fb0ba2c6250a83a966761ae70e2bfb4c2.webp) Galaxy A55 Continuous Integration ## CI/CD Integration Integrate TestingBot Maestro Testing with your CI/CD [![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[![GitHub](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) ## Frequently Asked Questions ### What is the advantage of running Maestro tests in the Cloud? TestingBot provides and maintains the infrastructure to run Maestro tests in parallel across multiple iOS and Android devices. You no longer need to maintain physical devices or simulators locally. TestingBot offers high-scale parallelization with easy integration in your CI/CD pipeline. All Maestro tests come with video recordings, logs and detailed execution reports. ### Is it possible to integrate Maestro testing in my CI/CD pipeline? Yes, you can easily integrate Maestro testing into your CI/CD pipeline using TestingBot's REST API. Upload your app and test flows, then trigger test execution from your CI/CD system. Results are returned in formats compatible with most CI/CD tools. TestingBot provides detailed test reports and can integrate with popular CI/CD platforms like Jenkins, GitHub Actions and GitLab CI. ### What devices can I test on with Maestro? TestingBot supports Maestro testing on various iPhone and Android devices, as well as simulators and emulators. You can test on different iOS versions, screen sizes and Android API levels to ensure comprehensive coverage. ### Where can I see the Maestro test results? Test results are available in real-time through the TestingBot dashboard, showing detailed execution logs and screenshots. Each test includes a complete video recording of the execution, making it easy to debug failures and verify test behavior. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Maestro Cloud Testing](https://testingbot.com/support/app-automate/maestro) - [Specifying Maestro Options](https://testingbot.com/support/app-automate/maestro/options) - [CI/CD integration setup guides](https://testingbot.com/support/integrations/ci-cd) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Maestro Testing? Please see our [Maestro Testing documentation](https://testingbot.com/support/app-automate/maestro) on how to get started. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/features/automation/xcuitest # XCUITest Cloud for iOS Automation Accelerate your XCUITesting capabilities with a remote iOS device grid. Upload your native iOS app (in Swift or Objective-C) and run XCUITests on hundreds of iPhone and iPad devices. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![XCUITest Cloud for iOS Automation](https://testingbot.com/assets/features/xcuitest-d5f410d972df3d0c1c4d1c2b3439f8dcaa1d23d41730bb74843bfb1f45997142.png) Trusted by some of the world's most innovative companies Getting Started ## How does it work? Get started with XCUITest testing in three simple steps 1 ### 1. Prepare your app & tests Create an .ipa file of your native iOS app, and a .zip file of your XCUI tests. Using XCode, with Swift or Objective-C. Test on multiple Apple hand held devices. 2 ### 2. Upload app and tests Upload your mobile app (in ipa format) and tests (.zip files) through the TestingBot REST API. [Learn more](https://testingbot.com/support/app-automate/xcuitest#upload) 3 ### 3. Run XCUI Tests Start the tests through an API call. The test results will appear in the TestingBot member area, together with a video, logs, viewport screenshots and other generated data. Use taps, swipe, zoom, scroll, or long press any element with XCUITest. Fast Execution ## Parallel Testing with XCUITest Speed up your release cycles with Parallel Testing on XCUITest Real Devices. Upload multiple apps and execute tests simultaneously for quicker, more efficient results. 10x Faster Testing 100+ Concurrent Tests [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing with XCUITest](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) Native Testing ## Test iOS apps with Swift and Objective-C Test your iOS apps with Swift and Objective-C on real devices with cloud-based XCUITest automation. - Native Swift & Objective-C support - Full XCUITest API compatibility - XCode integration ![Test iOS apps with Swift and Objective-C](https://testingbot.com/assets/features/xcuitest/xcuitest-21145751f857e1aa66815dbf0e7f5c8a1f45f6cd84748d9516ee1d4d7c2a2a59.png) Real Device Cloud ## XCUITest Real Device Cloud Test on real iPhones and iPads on the TestingBot cloud platform via XCUItest framework. TestingBot provides devices from iOS 12 up to iOS 18. - Latest iPhone & iPad models - Multiple iOS versions - Video recordings & logs [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 ![Test online on iPhone 16](https://testingbot.com/assets/devices/160h/33-c293dfd6742003e86ad82b583f9a5a226773067c2a23d100a4379ae82f6ebba2.webp) iPhone 16 ![Test online on iPhone SE 2022](https://testingbot.com/assets/devices/160h/31-e84c40c6867b3c43060fbaad0e698e01bac7c350cd15c52c23ab159916bbf1e2.webp) iPhone SE 2022 ![Test online on iPhone 15](https://testingbot.com/assets/devices/160h/27-ac62a400d382791601173f54045c190905de5eb4b927133c0ef5250735228494.webp) iPhone 15 ![Test online on iPad (8th generation)](https://testingbot.com/assets/devices/160h/26-70f7d18afde7620063a49a76cbfd088f8b59c742f3a5f4dd4a513dd6ec5c676c.webp) iPad (8th generation) Continuous Integration ## CI/CD Integration Integrate Apple's XCUI Testing with your CI/CD [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub Actions](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) Dedicated Infrastructure ## Private Device Cloud With Private Device Cloud, we take care of the setup, configuration and maintenance of dedicated devices exclusively for your company. Select your preferred devices, and we will make them available in our data center for seamless testing. - Dedicated devices for your team - Enhanced security & isolation - Priority support & SLA [Learn more](https://testingbot.com/enterprise/private-device-cloud) ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air Private Device ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 Private Device ![Test online on iPhone 16](https://testingbot.com/assets/devices/160h/33-c293dfd6742003e86ad82b583f9a5a226773067c2a23d100a4379ae82f6ebba2.webp) iPhone 16 Private Device ![Test online on iPhone SE 2022](https://testingbot.com/assets/devices/160h/31-e84c40c6867b3c43060fbaad0e698e01bac7c350cd15c52c23ab159916bbf1e2.webp) iPhone SE 2022 Private Device ![Test online on iPhone 15](https://testingbot.com/assets/devices/160h/27-ac62a400d382791601173f54045c190905de5eb4b927133c0ef5250735228494.webp) iPhone 15 Private Device ![Test online on iPad (8th generation)](https://testingbot.com/assets/devices/160h/26-70f7d18afde7620063a49a76cbfd088f8b59c742f3a5f4dd4a513dd6ec5c676c.webp) iPad (8th generation) Private Device ## Frequently Asked Questions ### What is the advantage of running XCUITests in the Cloud? You can run tests in parallel on multiple devices, drastically shortening the time it takes to run your entire test suite. No more need for an in-house device lab containing various iOS devices with different screen sizes and iOS versions. Take advantage of remote iOS devices, with various screen sizes and iOS versions. We do not provide jailbroken devices. ### How do I integrate cloud based XCUITesting in my CI/CD? Depending on the CI/CD service you are using, you can add multiple steps to achieve this. Create both an upload app step, to upload the files to TestingBot Storage. Finally, trigger the test run with our API. You can use our API to retrieve a JUnit XML report file, compatible with your CI/CD result parser. ### What other options are available during XCUI testing? You can change the network speed, language and locale of the device, change the GeoIP location and more. Test filters are also available. These allow you to control which tests will be executed from the test suite. ### Where can I see the XCUITest results? You can find the XCUITest results, together with video and logs in the member area. Using the REST API, you can fetch the results from our own CI/CD as well. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [XCUITest documentation](https://testingbot.com/support/app-automate/xcuitest) - [Localization testing with XCUITest](https://testingbot.com/support/app-automate/xcuitest/set-localization-options) - [IP Geolocation testing with XCUITest](https://testingbot.com/support/app-automate/xcuitest/set-ip-geolocation) - [List of available iOS physical devices](https://testingbot.com/support/app-automate/devices) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Appium Testing? To get started, please see our [XCUITest](https://testingbot.com/support/app-automate/xcuitest) documentation. [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Automate native iOS Apps with XCUITest](https://testingbot.com/assets/resources/articles/25-bb2ccb531384c461ef792214839e9e8f99a4b08b1293730ceeab67e4a8352563.webp)](https://testingbot.com/resources/articles/automate-native-ios-apps-xcuitest) #### [Automate native iOS Apps with XCUITest](https://testingbot.com/resources/articles/automate-native-ios-apps-xcuitest) Looking to automate native iOS apps? Read our XCUITest tutorial on how to use code for iOS automation. [Read more](https://testingbot.com/resources/articles/automate-native-ios-apps-xcuitest) [![Test your website and mobile apps on iOS 18.](https://testingbot.com/assets/blog/2024/ios18.webp)](https://testingbot.com/blog/ios-18-testing) #### [Test your website and mobile apps on iOS 18.](https://testingbot.com/blog/ios-18-testing) Ready to start testing on iOS 18? Get started today with TestingBot: run automated, visual and manual tests on iOS 18. [Read more](https://testingbot.com/blog/ios-18-testing) --- URL: https://testingbot.com/features/automation/appium # Appium Cloud Automation Appium is an automation tool for testing mobile applications. Run your mobile app automation tests on TestingBot's large grid of physical mobile devices and simulators. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Appium Cloud Automation](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) Trusted by some of the world's most innovative companies Platform Features ## Features of the TestingBot Appium Automation Platform ### Real Devices Run your Appium tests on physical mobile devices, without maintaining your own in-house device lab. ### Test artifacts Every test on TestingBot includes a video screencast of the device, along with logs and other generated artifacts. ### Native App Features Test native apps, push notifications, in-app purchases, media files and apps from the PlayStore, AppStore and through TestFlight. ### Geolocation Testing Run Appium tests with TestingBot's built-in geo-location testing feature. Choose from up to 20 regions around the globe. ### TestingBot Tunnel Run Appium tests against websites in a secure environment, such as a private network, staging environment or local machine. ### Gestures and Interactions Automate taps, swipes, scrolls and other interactions with Appium. ### App Uploads Upload mobile apps to TestingBot Storage for use in your tests. ### Network Throttling Throttle network speed to test how your app performs under different network conditions. Fast Execution ## Reduce Test Execution Time Run tests in parallel with the TestingBot mobile device cloud and accelerate test execution. Test seamlessly across a range of real devices for faster, more reliable results. [Get started free](https://testingbot.com/users/sign_up) ![Reduce Test Execution Time](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ![Replace your in-house Device Lab](https://testingbot.com/assets/features/appium/devicelab-75f7f33e3f397b019864f68f343211683c6d06a40e9334eda108d9f0d053297d.jpg) Device Lab ## Replace your in-house Device Lab Skip the hassle of buying, hosting, and maintaining iOS and Android devices. Instantly run your Appium tests on real devices in the TestingBot Mobile Cloud—accessible anytime, anywhere. Framework Support ## Appium Frameworks TestingBot integrates with various test frameworks and services. Easily convert your existing Appium tests and connect with your favorite CI/CD. ### [C#](https://testingbot.com/support/app-automate/appium/csharp) - [CSharp](https://testingbot.com/support/app-automate/appium/csharp) - [SpecFlow](https://testingbot.com/support/app-automate/appium/csharp/specflow) ### [NodeJS](https://testingbot.com/support/app-automate/appium/nodejs) - [CodeceptJS](https://testingbot.com/support/app-automate/appium/nodejs/codeceptjs) - [WebDriverIO](https://testingbot.com/support/app-automate/appium/nodejs/webdriverio) ### [Java](https://testingbot.com/support/app-automate/appium/java) - [TestNG](https://testingbot.com/support/app-automate/appium/java/testng) ### [PHP](https://testingbot.com/support/app-automate/appium/php) ### [Python](https://testingbot.com/support/app-automate/appium/python) ### [Ruby](https://testingbot.com/support/app-automate/appium/ruby) Continuous Integration ## Integrations with CI/CD services TestingBot integrates with the most popular CI/CD services, including Jenkins, Bamboo, TeamCity, Circle CI, GitLab CI and more. [ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![GitHub](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub ](https://testingbot.com/support/integrations/ci-cd/github-actions) Device Cloud ## Switch to Real Devices for 100% Accuracy Mobile emulators and simulators provide a basic preview, but they can't fully replicate real-world conditions. For accurate testing, choose TestingBot's real devices. [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-abb9a661ebbfa84f18bd6985d3e80330ad43fe4ea7d408157c87ae0f560a5ca1.webp) Pixel 9 ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-ba3caa0fe8fb834ea684e524f6ad690ca4f78402e85a51a48e94ad4dfcb93208.webp) Galaxy S25 ## Frequently Asked Questions ### How do I integrate Appium tests with my CI/CD pipeline? TestingBot integrates with all major CI/CD services, including Jenkins, CircleCI, GitLab CI, Travis CI and more. We provide sample scripts and API keys to get you up and running quickly, so your tests can be automatically triggered on each commit or deployment. The advantage of using TestingBot is that you can run your tests in parallel on multiple devices, drastically reducing the time it takes to run your entire test suite. ### Can I test native and hybrid apps with Appium on TestingBot? Yes! TestingBot fully supports testing native, hybrid, and mobile web applications using Appium. Whether your app is built with Flitter, React Native, Xamarin, Swift, Kotlin or Java, you can run your tests on real devices in the TestingBot cloud. ### Which Appium versions are supported? TestingBot supports all Appium versions, including Appium 1.x and Appium 2.x. ### Ready to start Appium Testing? To get started, please see our [Appium Testing](https://testingbot.com/support/app-automate/appium) documentation or [Book a Demo](https://testingbot.com/demo). [Start a free trial](https://testingbot.com/users/sign_up) Resources you may like [![Using Touch Actions with Appium](https://testingbot.com/assets/resources/articles/24-490f70ad8a80e4534523707125b88e44e70fe19b126be4f44e689bbd5f6a0cbf.webp)](https://testingbot.com/resources/articles/touch-actions-appium) #### [Using Touch Actions with Appium](https://testingbot.com/resources/articles/touch-actions-appium) Find out how to use Touch Actions with Appium. [Read more](https://testingbot.com/resources/articles/touch-actions-appium) [![Migrate from Appium 1.x to Appium 2.x](https://testingbot.com/assets/resources/articles/27-121da26036885301ba438e1cdfc81e7ae8045cbc53c0dafaff5b4436000590b1.webp)](https://testingbot.com/resources/articles/appium-2-migration) #### [Migrate from Appium 1.x to Appium 2.x](https://testingbot.com/resources/articles/appium-2-migration) Learn how to migrate from Appium 1 to the new Appium 2. [Read more](https://testingbot.com/resources/articles/appium-2-migration) [![Dark Mode Testing with Appium](https://testingbot.com/assets/resources/articles/22-ed15fa0f3fde7566416fff5078b44689dc274439b2fb829f8c68603e909a65d6.webp)](https://testingbot.com/resources/articles/dark-mode-testing) #### [Dark Mode Testing with Appium](https://testingbot.com/resources/articles/dark-mode-testing) Perform dark mode automated testing on iOS and Android with Appium. [Read more](https://testingbot.com/resources/articles/dark-mode-testing) ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Appium 3](https://testingbot.com/support/app-automate/appium/appium-versions) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) --- URL: https://testingbot.com/test-in-internet-explorer # Internet Explorer Testing Easily test on Internet Explorer Online! Instant access to any IE Browser versions (7-11). Test your website on real IE browsers. No IE Emulators or Simulators. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/ie-075955285f8005808f3d26947aace877f96e5843a33bd4d6e997709d3a294451.svg) Trusted by some of the world's most innovative companies Interactive Testing ## Interactive Testing On Internet Explorer Browsers ### IE 11, IE 10, IE 9, IE 8, IE 7 Run tests on any version of internet explorer, on real Windows desktops. ### Responsive Testing Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### No more VMs No more VMs to be maintained or software to be installed. TestingBot has you covered. ### +5200 combinations Instant access to any browser on Mac, Linux, Windows and Mobile. Real Browsers ## IE Emulators vs Real Internet Explorer Browsers Internet Explorer emulators do not always show correct results. Test on real IE browsers, running on a real Windows operating system. No Emulators, Simulators or Virtual Machines, try TestingBot and get instant access to a real IE browser. [Get started free](https://testingbot.com/users/sign_up) Global Testing ## Geolocation Testing on IE Perform **geolocation testing** in various regions across the world. Test Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. Visual Testing ## Automated IE Screenshots Take automated screenshots of your website on various IE versions. Rapidly test your webpages for visual differences across multiple IE browsers. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Local Cross Browser IE Testing Use the secure [TestingBot Tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any IE browser version. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any browser in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### Why do I need to test my website on Internet Explorer? Internet Explorer (IE) has a market share of about 5% in the global browser market. Some organizations or websites are designed to only allow IE, while blocking other browsers for security reasons. IE is the default browser on most of the (older) Windows editions, which means a large portion of Windows users will use this browser. ### What is an Internet Explorer (IE) emulator? An Internet Explorer emulator acts as if it is an Internet Explorer browser. It tries to help developers and testers to test their websites on Internet Explorer. Because this is an emulator, it is not accurate enough to use this for testing. TestingBot recommends using its IE browsers running on real desktops, no emulator. ### Why should I not test with an IE emulator? IE Emulators only mimic an Internet Explorer browser screen and User-Agent. It runs slower than a real IE browser and is not as accurate. You cannot accurately test the CSS support of IE with an emulator. If you are using macOS or Linux, your choices are to install a Windows VM or use a cloud service such as TestingBot. ### How does TestingBot help with internet browser testing? TestingBot provides a grid of real browsers, including IE7 up to IE11, which you can use for automated and manual testing. Run a manual IE test on Windows 8, 8.1 or 7. Or perform automated tests on IE7 up to IE11. ### Can I use macOS or Linux to test on IE? If your computer is a macOS or Linux device, we recommend using TestingBot's cloud service to access a IE browser instance. No need to download, install and maintain a Windows VM. Use TestingBot's interactive, browser-based, remote IE service. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start IE Testing? Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/test-edge-browser # Online Cross Browser Testing On Microsoft Edge Browser Easily test on Microsoft Edge Online! Make sure your website works on the latest Edge browser versions that come with Microsoft Windows. Test your website on real Edge browsers. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg) Trusted by some of the world's most innovative companies Interactive Testing ## Interactive Testing On Internet Explorer Browsers ### Legacy versions up to the latest version Run tests on various Microsoft Edge versions, on real Windows and macOS desktops. ### Responsive Testing Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### No more VMs No more VMs to be maintained or software to be installed. TestingBot has you covered. ### +5200 combinations Instant access to multiple Microsoft Edge browsers, on Windows and macOS. Real Browsers ## Microsoft Edge Emulators vs Real Microsoft Edge Browsers Microsoft Edge emulators do not always show correct results. Test on real Microsoft Edge browsers, running on a real Windows operating system. No Emulators, Simulators or Virtual Machines, try TestingBot and get instant access to a real Microsoft Edge browser. [Get started free](https://testingbot.com/users/sign_up) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg) Global Testing ## Geolocation Testing on Microsoft Edge Perform \geolocation testing\ in various regions across the world. Test Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. Visual Testing ## Automated Microsoft Edge Screenshots Take automated screenshots of your website on various Microsoft Edge versions. Rapidly test your webpages for visual differences across multiple Microsoft Edge browsers. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Local Cross Browser Microsoft Edge Testing Use the secure [TestingBot Tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any Microsoft Edge browser version. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any browser in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### Why do I need to test my website on Microsoft Edge? Microsoft Edge is a popular browser that comes by default on new Microsoft Windows installations. It has a market percentage of 6% globally. It's important to make sure your website looks and behaves correctly on this web browser. ### How does TestingBot help with Microsoft Edge testing? TestingBot provides an online cloud of Microsoft Edge browsers, running on Windows and macOS machines. You can run manual tests on Edge browsers, or use WebDriver automation to automatically test your website. ### Can I use Microsoft Edge on macOS? TestingBot provides macOS machines equipped with multiple versions of Microsoft Edge. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Microsoft Edge Testing? Start testing your apps with TestingBot. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/test-on-safari # Safari Browser Testing Test Safari online, running on macOS and iOS. No emulators or simulators, only Safari running on real Apple devices and physical mobile devices. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg) Trusted by some of the world's most innovative companies Safari Testing ## Test On Different Safari Browsers Online ### Developer Tools Interactively test your website with Safari's native Developer Tools. ### Safari 12 up to 26 Instant access to different Safari versions, test on real Apple products. ### macOS Desktop - macOS Tahoe - Safari 26 - macOS Sequoia - Safari 18 - macOS Sonoma - Safari 17 - macOS Ventura - Safari 16 - macOS Monterey - Safari 15 - macOS Big Sur - Safari 14 - macOS Catalina - Safari 13 - macOS Mojave - Safari 12 ### Safari iOS - iOS 26 - iOS 18 - iOS 17 - iOS 16 - iOS 15 - iOS 14 - iOS 13 - iOS 12 Mobile Testing ## Safari Testing On Windows Machines Are you using Windows on your computer and want to test something on Safari? No need to setup a virtual machine, simply test your website on a remote Safari desktop browser in the cloud. It does not matter if you are using Windows 11, 10, Vista or XP on a laptop, PC or any other device. TestingBot will stream the contents of a remote macOS machine to your screen. Test any version of Safari on Windows, developer tools included. TestingBot provides access to various Safari versions, ranging from Safari 12 up to 26 on Desktop and Mobile Safari running on iOS 12 up to 26. [Get started free](https://testingbot.com/users/sign_up) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg) Global Testing ## Geolocation Testing on Safari Every test comes with access to generated artifacts, including screenshots, logs and a video of the test. Visual Testing ## Automated Safari Screenshots Take automated screenshots of your website on various Safari versions, running on macOS desktops. Perform visual comparison testing with various Safari versions, running on various macOS versions: OSX Yosemite up to macOS Tahoe [Get started free](https://testingbot.com/users/sign_up) ![Superfast, live cross browser testing](https://testingbot.com/assets/features/safari/safari-screenshots-4277b734fe08a1b242b21afdfbe3025f188374c2330de1b44b20aac99cabc41c.jpg) Beta Testing ## Safari Tech Preview & Safari Beta Manual, Automated and Visual testing on Safari Technology Preview and Safari Beta. Make sure your website works and looks correctly on Apple's upcoming Safari web browser versions. [Get started free](https://testingbot.com/users/sign_up) ![Superfast, live cross browser testing](https://testingbot.com/assets/features/safaritech-df707beff7e14733fd751d5a48b2b20dc5f4ef312022e0e2c6548994fb905a71.png) Extensions ## Testing Safari Extensions Easily load unsigned Safari App Extensions, Web Extensions (Xcode) and Safari Web Extensions (18.4+) on TestingBot, available for manual sessions and CI-driven automated tests. [More information](https://testingbot.com/support/web-automate/selenium/browser-extension#safari) ![Safari Extension Testing](https://testingbot.com/assets/features/safari/safari-extension-c0d931000dcc6adcdf9b4cd1f93fe67d6ab8b906deae59c1a6d0bcfcd15493d3.webp) Appium Testing ![Appium Cloud Automation](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) ## Automated Mobile Safari Testing with Appium Use [Appium](https://testingbot.com/features/automation/appium) to connect to our grid of physical iOS devices and run automated mobile Safari tests against your website. ### Parallel Testing Run multiple Appium tests simultaneously, shortening your total Appium execution time. ### Write your tests in any language Since Appium uses the WebDriver API, you can write your tests in any language and run on TestingBot. ### Device Coverage Test on the [devices](https://testingbot.com/support/app-automate/devices) that matter, representing a large share of global device usage. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Local Cross Browser Safari Testing Use the secure [TestingBot Tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any Safari browser version on macOS and iOS. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any browser in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### Why do I need to test my website on Safari? Safari has a market share of about 4% in the global browser market. This browser is built and maintained by Apple and supports all the latest browser technologies. Safari is the default browser on all macOS operating systems, which means a large portion of macOS users will use this browser for their day-to-day browsing. Test Safari's private browsing capabilities, open multiple tabs or test the cross site tracking prevention. ### What is Safaridriver? Safaridriver is a utility, shipped by default in every macOS operating system, which allows Selenium to automate Safari through a HTTP based API. To use Safaridriver, you need to make sure it is enabled by running this command in a terminal window: `safaridriver --enable` ### How can I automate Mobile Safari? We recommend using Appium, which has built-in support to communicate with iOS Safari. Simply run your Appium scripts against the TestingBot device grid. TestingBot will instruct the iOS device to open Safari. Your Appium script will then instrument the mobile Safari browser in an automated way. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Safari Testing? Start testing your website on Safari, running on macOS and iOS devices. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/test-on-chrome # Chrome Testing Test on real Chrome browsers, running on Windows, macOS and Linux. Real Chrome browsers from Google, available for automated, visual and manual testing. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Superfast, live cross browser testing](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg) Trusted by some of the world's most innovative companies Key Features ## Test On Different Chrome Versions Online ### Developer Tools Test your website with Chrome's DevTools. Inspect and debug with your mouse and keyboard. ### Responsive Chrome Testing Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### Chrome Beta and Dev Testing Make sure your website works and looks correctly on upcoming Chrome versions. ### Chrome 35 up to latest Test on previous Chrome versions, from Google Chrome 33 until the latest. ![Chrome Testing](https://testingbot.com/assets/features/chrome/chrome-testing-be671e473be9fb7594f6f27c272e82b110a1d9c423cc5aec71a60bfea3e876ef.jpg) Mobile Testing ## Browser Testing on Real Chrome Browsers Start testing on real Chrome browsers in the cloud. Interactively test with your mouse and keyboard, or run automated tests on any version of Chrome. Uncover functional bugs or design mistakes on various version of Google Chrome. Test the performance and compatibility of your website on Google's Chrome browser. Global Reach ## Geolocation Testing on Chrome Run Chrome browsers from multiple countries around the world. Test Samsung Galaxy Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, France, Germany, United Kingdom, United States and more. Supported Frameworks - [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)Selenium](https://testingbot.com/features/automation/selenium) - [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/features/automation/appium) - [![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)Cypress](https://testingbot.com/features/automation/cypress) - [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/features/automation/puppeteer) - [![Playwright Testing](https://testingbot.com/assets/support/playwright-a1cdc007042f46efa0437b42fd6381a449e1d37acc0f59102c244913fb665890.png)Playwright](https://testingbot.com/features/automation/playwright) ## Automated Testing on Chrome Run automated tests with Chrome and the Chrome for Testing browser. You can use Selenium, Puppeteer or Playwright to run automated tests on a virtual browser. The TestingBot online Chrome instances run on Windows, macOS, Linux and Android. Chrome Testing ## Chrome Beta, Canary and Chrome for Testing TestingBot uses Chromedriver to run automated and manual tests on Chrome browsers, including the Chrome for Testing browser, Chrome beta browser and Canary builds. ## Chrome Browser Testing ### Performance Testing Test the performance of your website with speed tests such as Lighthouse and Chrome's DevTools. ### Chrome Extensions Automated or manual testing of Chrome extensions on various Chrome versions and platforms. ### Camera, Microphone and WebGL Testing Test with dummy Camera and Microphone. Run WebGL tests in the cloud. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Local Cross Browser Chrome Testing Use the secure [TestingBot Tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any Chrome browser version. Test localhost websites with Puppeteer, Playwright and Selenium. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any browser in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### Why do I need to test my website on Chrome? Chrome is the most popular webbrowser on the planet, it has over 60% market share globally. You want to make sure that your website looks and functions correctly on this browser. The browser is promoted and built by Google and is used all around the world, on various platforms and devices. ### What is Chromedriver? Chromedriver is a program which you can download to automate the Chrome browser. It is used by developers and testers to perform actions in Chrome. For example, with Selenium, Puppeteer and Playwright, it is used to run tests against websites. Chromedriver depends on the version of Chrome, which means you need to make sure the Chromedriver version matches the browser version. At TestingBot, this is done automatically for you when you run tests. ### What is the difference between Chrome, Chromium and Chrome for Testing? Chrome is the browser that everyone uses to do their day-to-day browser. It is the browser that TestingBot provides for testing as well. Chromium uses the same browser engine but does not come with specific branding by Google, it is open-source. Chrome for Testing is a flavor of Google Chrome specifically built for testing, it does not contain the auto-update functionality and is optimized for running automated tests. ### How does TestingBot help with Chrome browser testing? TestingBot provides a grid of Chrome browsers, from version 35 up to the latest version and beta/dev versions. All Chrome tests come with a video, logs generated by the browser and Chromedriver, and various other meta-data. ### Is this a Chrome emulator? All the Chrome browsers on TestingBot are real, they are downloaded straight from Google. Our virtual browsers run just like they would on any other computer. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start Chrome Testing? Start testing your applications on Chrome browser today with our comprehensive testing platform. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/test-on-iphone # Online Testing on iPhone & iOS devices Test your iOS mobile app or website on a wide range of real iOS devices. Instant access to devices such as iPhone 15, iPhone 14, iPhone 13, iPhone 12, iPhone XR, iPhone 6s, iPad and more iOS devices. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Website and mobile app testing on iPhone](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg) Trusted by some of the world's most innovative companies Key Features ## Test On Different iPhones Online ### Wide range of iPhone devices Test your mobile apps and websites on physical mobile iPhones. Choose from a range of iPhones, from iPhone 6s to iPhone 17. ### Real iOS Device Cloud Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### Secure and private TestingBot provides pristine iPhones and the possibility of private iPhone devices. ### Real-time debugging Debug your websites & mobile apps. Access crash reports and logs to instantly fix bugs. ### Tap, Swipe, Pinch & more Interact with a physical, remote iOS device, just like you would while holding it in your hand. Tap, swipe, pinch and perform other gestures. ### Test various network speeds Run iPhone tests with different network speeds: choose between WiFi, 5G, 4G, Edge and more. iPhone Models ## Real iPhone and iOS Devices for Testing If you don't have an iPhone device to test on, simply connect to a physical device in TestingBot's datacenter. You will get instant access to a physical iPhone. TestingBot provides iPhones ranging from iPhone 6s to iPhone 17. - [iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - iPhone 11 - iPhone X - iPhone XR - iPhone 8 ![Parallel Testing](https://testingbot.com/assets/features/iphone/iphone-stack-eb298d28ef6ad2d6e0df8c2501c1d39d75ea644613128c94e05ca2d88dd158c0.jpg) Geolocation ## Geolocation Testing on iPhones Perform geolocation testing in various regions across the world. Test iPhone Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. Screenshots ## Responsive Testing On iPhone Choose between various iPhone devices with different screen sizes to perform responsive testing. Rotate the device for landscape and portrait mode testing. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/iphone/iphones-0b63ad1776aeba250ec3267b812d4444b10d5a814d701332120e465724288789.webp) ![Appium Cloud Testing](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) Appium Testing ## Automated iPhone Testing with Appium Use [Appium](https://testingbot.com/features/automation/appium) to connect to our grid of physical iOS devices and run automated mobile Safari tests against your website. ### Parallel Testing Run multiple Appium tests simultaneously, shortening your total Appium execution time. ### Write your tests in any language Since Appium uses the WebDriver API, you can write your tests in any language and run on TestingBot. ### Reliable Service Test on a reliable platform, with zero test flakiness. Ship your website and mobile app with confidence. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Local Testing ## Local iPhone Testing Use our [secure tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any Safari browser version on macOS and iOS. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any iPhone in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) Real Devices ## iOS Real Device Testing Test your website or mobile app on a real iOS device. Instant access to a physical iPhone or iPad. [View Devices](https://testingbot.com/support/app-automate/devices) ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 ![Test online on iPhone 16](https://testingbot.com/assets/devices/160h/33-c293dfd6742003e86ad82b583f9a5a226773067c2a23d100a4379ae82f6ebba2.webp) iPhone 16 ![Test online on iPhone SE 2022](https://testingbot.com/assets/devices/160h/31-e84c40c6867b3c43060fbaad0e698e01bac7c350cd15c52c23ab159916bbf1e2.webp) iPhone SE 2022 ![Test online on iPhone 15](https://testingbot.com/assets/devices/160h/27-ac62a400d382791601173f54045c190905de5eb4b927133c0ef5250735228494.webp) iPhone 15 ![Test online on iPad (8th generation)](https://testingbot.com/assets/devices/160h/26-70f7d18afde7620063a49a76cbfd088f8b59c742f3a5f4dd4a513dd6ec5c676c.webp) iPad (8th generation) FAQ ## Frequently Asked Questions ### How to test a mobile app on iPhone? Testing your iOS app on a variety of iOS devices is important before publishing to the App Store. TestingBot allows you to upload and test your app on a number of different iPhones. Choose between various iOS versions and screen resolutions, to make sure your mobile app works on all iPhone devices. ### Why use a real device instead of an iOS simulator? Running an iOS simulator or emulator is slow. It is slow to start up and interact with, since it's mimicking a full OS on a currently running OS. Simulators do not mimic the exact performance of the iOS device they're simulating. Some apps and services are missing as well, for example the Schoolwork app (using Classkit). ### Why is testing your website on an iPhone necessary? iPhone has a 28% global market share, it's important to make sure your website looks and behaves correctly on iPhones. Safari is the default browser on iPhones, so you should test your website on mobile safari to make sure iPhone users have a good experience. Testing on Chrome or Firefox does not represent iPhone users. ### What is TestingBot's Real Device Cloud? TestingBot provides a grid of physical iPhones, ready to run your manual and automated tests. No need to purchase, setup and maintain your own collection of iPhones. Rely on TestingBot for your iOS testing. ### Can I test Safari on iPhone? TestingBot provides access to unaltered iPhones. These come straight from the store and are not jailbroken. Run your tests on real mobile safari browsers, on physical iPhones in our datacenter. ### Ready to start iPhone Testing? Get started with iPhone testing in minutes. No credit card required. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/integrations 36+ Integrations # Integrations TestingBot integrates with various third-party services and products. ### Categories [Automation Framework 8](https://testingbot.com#automation)[Project Management 4](https://testingbot.com#project)[CI/CD 10](https://testingbot.com#ci)[Record and Playback 7](https://testingbot.com#record)[App Distribution 1](https://testingbot.com#distribution)[Browser Extension 1](https://testingbot.com#extension)[Marketplace 4](https://testingbot.com#marketplace)[Other 1](https://testingbot.com#other) [Request Integration](https://testingbot.com/contact/new) ## Automation Framework Run tests with popular testing frameworks [ ![Selenium](https://testingbot.com/assets/integrations/selenium-1403d7bf83f64f56f05cea3fe50ae45bc3025d5a2433b7b05d2b199fec753cf6.svg) ### Selenium Run tests on our grid with 5200+ browsers ](https://testingbot.com/support/web-automate/selenium)[ ![Appium](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) ### Appium Test native, hybrid and webapps on real devices ](https://testingbot.com/support/app-automate/appium)[ ![Cypress](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg) ### Cypress Run Cypress tests on macOS and Windows ](https://testingbot.com/support/web-automate/cypress)[ ![Puppeteer](https://testingbot.com/assets/integrations/puppeteer-7bb02294d7d9ef0b92e56f08d1bf99574298111ee79de39d298ea99efb17f322.svg) ### Puppeteer Testing with Puppeteer in the cloud ](https://testingbot.com/support/web-automate/puppeteer)[ ![Playwright](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg) ### Playwright Testing with Playwright in the cloud ](https://testingbot.com/support/web-automate/playwright)[ ![Espresso](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg) ### Espresso Mobile app testing on Android ](https://testingbot.com/support/app-automate/espresso)[ ![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg) ### XCUITest Automated testing on iOS ](https://testingbot.com/support/app-automate/xcuitest)[ ![Maestro](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg) ### Maestro Testing on iOS and Android ](https://testingbot.com/support/app-automate/maestro) ## Project Management Connect with your favorite project tools [ ![Slack](https://testingbot.com/assets/integrations/slack-935c2233d65c4fd7ce6ac282c0abe685fcc2ed73d5d814083a071ecd4557befa.webp) ### Slack Get notified when tests finish or fail ](https://testingbot.com/support/integrations/slack)[ ![Jira](https://testingbot.com/assets/integrations/jira-d8877a4e3d87725f3279afa510d0d951d204d8bc46751a1f1051d477aaa00afe.svg) ### Jira Create issues with test meta-data ](https://testingbot.com/support/integrations/jira)[ ![Bugsnag](https://testingbot.com/assets/integrations/bugsnag-3e0b2bebfb3c599b8d986dda1bd59712ae70de4a9450b7522a698ad786ff6e62.svg) ### Bugsnag Create issues with screenshots ](https://testingbot.com/support/integrations/bugsnag)[ ![ZebRunner](https://testingbot.com/assets/integrations/zebrunner-51fe5d07743785e67d69f0c97a8ae327e89a01545a54662e5cf1cf3c24601bf4.svg) ### ZebRunner Smart analysis of test results ](https://testingbot.com/support/integrations/zebrunner) ## CI/CD Integrate with your continuous integration pipeline [ ![TeamCity](https://testingbot.com/assets/integrations/teamcity-7e75cdb835903a4983ad276c41d95e569ceac5be486e96ec1f955029ce5bb319.svg) ### TeamCity Plugin for JetBrains TeamCity ](https://testingbot.com/support/integrations/ci-cd/teamcity)[ ![Jenkins](https://testingbot.com/assets/integrations/jenkins-e586a1c4af833e4c8d38d7b392a4e84bd193f30cae9cf8c9f198a58ec943a1ff.webp) ### Jenkins Pipeline + tunnel support ](https://testingbot.com/support/integrations/ci-cd/jenkins)[ ![Bamboo](https://testingbot.com/assets/integrations/bamboo-c8fe09a3cb0b74d6055e3aa6607d77720bfe29ff487b8e3cf825138adf634346.svg) ### Bamboo Atlassian Bamboo plugin ](https://testingbot.com/support/integrations/ci-cd/bamboo)[ ![Azure DevOps](https://testingbot.com/assets/integrations/devops-7de50ed101385e09ac3fb0b1110a601e229282512a1b25460fdaedd22ef244bb.webp) ### Azure DevOps Integrate with VSTS ](https://testingbot.com/support/integrations/ci-cd/azure)[ ![CircleCI](https://testingbot.com/assets/integrations/circleci-ede029654ff39b60342e4a5bba8fc9a3a49305cc38bda215b7cf8d07e85e0543.webp) ### CircleCI Integrate with CircleCI ](https://testingbot.com/support/integrations/ci-cd/circleci)[ ![Bitbucket Pipelines](https://testingbot.com/assets/integrations/bitbucket-02aabcd549221726e052f2ee19c8959fbb218160ad7f7c31f6e6b96e7824a42c.webp) ### Bitbucket Bitbucket Pipelines integration ](https://testingbot.com/support/integrations/ci-cd/bitbucket)[ ![GitLab](https://testingbot.com/assets/integrations/gitlab-e4c0b6db07d07bc0a400f5606e258f4dc8a51b778e97bbfa51d1d531f3cb049a.webp) ### GitLab Integrate with GitLab CI ](https://testingbot.com/support/integrations/ci-cd/gitlab)[ ![Travis CI](https://testingbot.com/assets/integrations/travis-f3a8872deab0dd6f4c13686fd8255cb07c426309090e335a9198312b49c43232.webp) ### Travis CI Integrate with Travis CI ](https://testingbot.com/support/integrations/ci-cd/travis-ci)[ ![GitHub Actions](https://testingbot.com/assets/integrations/github-actions-8436242ad9e15381f84f1a98a10dddce15611087f121d6305782e211942b7842.webp) ### GitHub Actions Launch tests from workflows ](https://testingbot.com/support/integrations/ci-cd/github-actions)[ ![Bitrise](https://testingbot.com/assets/integrations/bitrise-d122449f8ba4609306287a7080cef27601f50d50b7bdf23811751de4d5ea41d6.svg) ### Bitrise Mobile app CI/CD integration ](https://testingbot.com/support/integrations/ci-cd/bitrise) ## Record and Playback Create tests without writing code [ ![Selenium IDE](https://testingbot.com/assets/integrations/seleniumide-3a54afafe6c839d7e91eeb612d1bb393891df598274ecadb3557386ab2a7ab5c.webp) ### Selenium IDE Record with browser extension ](https://testingbot.com/support/web-automate/codeless-automation/add-test)[ ![Katalon Studio](https://testingbot.com/assets/integrations/katalon-497d6adbf9a9bb1ed8b5c9b9d6b8ded1b45dfb63a3386b572a0401515e4377ca.webp) ### Katalon Studio Record and run on TestingBot ](https://testingbot.com/support/web-automate/selenium/katalon-studio)[ ![Oxygen IDE](https://testingbot.com/assets/integrations/oxygen-9f738def7a7dd59f3768f44346e0fdba21ea1d9d68131c8bb474d56ccc73b1d2.webp) ### Oxygen IDE Record and playback tests ](https://testingbot.com/support/web-automate/selenium/oxygen)[ ![Ranorex Studio](https://testingbot.com/assets/integrations/ranorex-180a3aafc4fbb4b4d78a0d99af328c33256d85e5d7fad77c0a75a67e40ddcb69.webp) ### Ranorex Studio Record and run tests ](https://testingbot.com/support/integrations/ranorex)[ ![Cerberus](https://testingbot.com/assets/integrations/cerberus-21bf19476562da6ec6b57ca5acdc63bada4fa7093018801ecb2a83b9c5edb98e.webp) ### Cerberus Run Cerberus tests ](https://testingbot.com/support/integrations/cerberus)[ ![Tricentis Tosca](https://testingbot.com/assets/integrations/tricentis-tosca-89d025a6a71944c379e9ef745466c8b65c6af8141d72350e2bc6c33ab85b6da8.webp) ### Tricentis Tosca Run Tosca tests ](https://testingbot.com/support/integrations/tricentis-tosca)[ ![QMetry](https://testingbot.com/assets/integrations/qmetry-0647488fc2248e9e180e384e614b8cdbd1e8e4cf5360ab450d65a512490b0405.svg) ### QMetry Codeless test automation ](https://testingbot.com/support/integrations/qmetry) ## App Distribution Test apps from distribution platforms [ ![Microsoft App Center](https://testingbot.com/assets/integrations/app-center-icon-2c5c0d6c296fd04d1d3d0109db02dde20bb93a5ee7a9616e7805f27d6ec6503a.svg) ### App Center Test apps from Microsoft App Center ](https://testingbot.com/support/integrations/appcenter) ## Browser Extension Test instantly from your browser [ ![TestingBot Extension](https://testingbot.com/assets/logo-head-c3ea57ac5c8158d3f911af8093ee89e02c51e3e27f82c678cf90fc9e0d66cc6c.svg) ### TestingBot Extension Test any webpage instantly ](https://testingbot.com/support/web-live/extension) ## Marketplace Available in popular marketplaces [ ![Shopify](https://testingbot.com/assets/integrations/shopify-13ec81d945cb953040bdeaf32d5267978c2d33e428ec46fc2103362cbc2cf0f7.svg) ### Shopify Test your Shopify store ](https://apps.shopify.com/testingbot-1)[ ![Semrush](https://testingbot.com/assets/integrations/semrush-6ea828d5e278d18118745e756c0e8359432ccbc3834045c57b6818f39d21ab92.webp) ### Semrush Test on 100+ browser combinations ](https://www.semrush.com/apps/ai-website-testing/)[ ![Wix](https://testingbot.com/assets/integrations/wix-1647c811fea6aa58639da859a0e269d000ae67d85beca20d18d95e8951285192.svg) ### Wix Test your Wix website ](https://www.wix.com/app-market/web-solution/website-testing)[ ![AWS](https://testingbot.com/assets/integrations/aws-37fe010e66887d20cd831130e90da33a0ec731b5dd87fbba8adc933db17b0709.webp) ### AWS Marketplace License through AWS ](https://aws.amazon.com/marketplace/seller-profile?id=seller-k6mxju5cqvrp4) ## Other Additional tools and integrations [ ![Appium Desktop](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg) ### Appium Inspector Visualize and inspect mobile app elements ](https://testingbot.com/support/integrations/appium-desktop) --- URL: https://testingbot.com/test-on-ipad # Online Testing on iPad Devices Test your iOS mobile app or website on a wide range of physical iPad devices. We provide access to devices such as iPad 8th generation, iPad 6th generation and more iOS devices. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Online iPad testing for websites and apps](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg) Trusted by some of the world's most innovative companies Key Features ## Test On Different iPads Online ### Wide range of iPad devices Test your mobile apps and websites on physical iPads. Choose from a range of iPads, from iPad 6th generation to iPad 8th generation. ### Real iPad Device Cloud Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### Secure and private TestingBot provides pristine iPad devices with the possibility of private iPad devices. ### Real-time debugging Debug your websites & mobile apps. Access crash reports and logs to instantly fix bugs. ### Tap, Swipe, Pinch & more Interact with a physical, iPad iOS device. Just like you would, while holding it in your hand. Tap, swipe, pinch and perform other gestures. ### Test various network speeds Run iPad tests with different network speeds: choose between WiFi, 5G, 4G, Edge and more. iPad Testing ## Real iPad Devices for Testing If you don't have an iPad device to test on, simply connect to a physical device in TestingBot's datacenter. You will get instant access to a physical iPad. TestingBot provides iPads ranging from iPad 6th generation to iPad 8th generation. [Get started free](https://testingbot.com/users/sign_up) ![Parallel Testing](https://testingbot.com/assets/features/ipad/ipad-754cb9743cb5015d24552e9684c20ea56c413dd88d1c913667a5e53708aa129c.webp) Geolocation ## Geolocation Testing on iPads Perform geolocation testing in various regions across the world. Test iPad Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, United Kingdom, United States, Germany, France, Spain, China and more. Screenshots ## Responsive Testing On iPad Choose between various iPad devices with different screen sizes to perform responsive testing. Rotate the device for landscape and portrait mode testing. [Get started free](https://testingbot.com/users/sign_up) ![Responsive Testing On iPad](https://testingbot.com/assets/features/iphone/iphones-0b63ad1776aeba250ec3267b812d4444b10d5a814d701332120e465724288789.webp) Appium Testing ![Appium Cloud Testing](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) ## Automated iPad Testing with Appium Use [Appium](https://testingbot.com/features/automation/appium) to connect to our grid of physical iPads and run automated mobile tests against your website or mobile app. ### Real Devices Run your Appium tests on physical mobile devices, without maintaining your own in-house device lab. ### Geolocation Testing Run Appium tests with TestingBot's built-in geo-location testing feature. Choose from up to 20 regions around the globe. ### Reliable Service Test on a reliable platform, with zero test flakiness. Ship your website and mobile app with confidence. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Local Testing ## Local iPad Testing Use our [secure tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on any Safari browser version on iPad. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any iPad in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### How to test a mobile app on iPad? Testing your iOS app on a variety of iPad devices is important before publishing to the App Store. TestingBot allows you to upload and test your app on a number of different iPads. Choose between various iOS versions and screen resolutions, to make sure your mobile app works on all iPad devices. ### Why use a real iPad device instead of an iOS simulator? Running an iOS simulator or iOS emulator is slow to start and use. Simulators are running a virtualized version of iOS and can not be compared to using iOS on a physical device. Physical devices have different chipsets and hardware. Simulators do not mimic the exact performance of the iOS device they're simulating. Some apps and services are missing as well, for example the Schoolwork app (using Classkit). Simulators can not mimic exact device hardware configurations, which means battery consumption measurements for example can not be performed accurately. ### Why is testing your website on an iPad necessary? iPads have a 30% global market share, it's important to make sure your website looks and behaves correctly on iPad. Safari is the default browser on iPad, so you should test your website on mobile safari to make sure iPad users have a good experience. Test your website in portrait and landscape mode to make sure your website and apps work 100% correct on tablets. ### What is TestingBot's Real Device Cloud? TestingBot provides a grid of physical iPad devices, ready to run your manual and automated tests. No need to purchase, setup and maintain your own collection of iPad devices. Rely on TestingBot for your iOS testing. ### Can I test Safari on iPad? TestingBot provides access to unaltered iPads. These come straight from the store and are not jailbroken. Run your tests on real mobile safari browsers, on physical iPad devices in our datacenter. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) ### Ready to start iPad Testing? Start testing your apps on iPad devices today with TestingBot's cloud platform. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/test-on-galaxy # Online Samsung Galaxy Devices Start testing and interacting with real Android devices, including Samsung Galaxy S24, Galaxy S23, Galaxy S21, Galaxy S20, Galaxy S10, S8, Galaxy Tabs and more. Signup & Start Testing for Free! [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Test on Samsung Galaxy Devices (S8 - S24) & Tabs](https://testingbot.com/assets/environments/svg/android-1b3d235e17522e2238e1c55b4e9cdd41219f653cd958ea065877d3813f32ffc3.svg) Trusted by some of the world's most innovative companies Key Features ## Test On Galaxy Devices Online ### Wide range of Samsung Galaxy devices Test your mobile apps and websites on physical Samsung Galaxy devices. Choose from a range of Android Galaxy versions, including Galaxy S23. ### Physical Android Device Cloud Each test on TestingBot comes with a video screencast of the device, logs and other generated artifacts. ### Secure and private TestingBot provides physical Galaxy devices, without any modification. ### Real-time debugging Debug your websites & mobile apps. Access crash reports and logs to instantly fix bugs. ### Tap, Swipe, Pinch & more Interact with a physical Galaxy device. Tap, swipe, pinch and perform other gestures, just like you would while holding it in your hand. ### Test various network speeds Run Android tests with different network speeds: choose between WiFi, 5G, 4G, Edge and more. Galaxy Devices ## Real Samsung Galaxy Devices for Testing If you don't have a Galaxy Android device to test on, simply connect to a physical one in TestingBot's datacenter. - Galaxy S24 - Galaxy S23 - Galaxy S21 - Galaxy S20 - Galaxy S10 - Galaxy Tab [Get started free](https://testingbot.com/users/sign_up) ![Real Samsung Galaxy Devices for Testing](https://testingbot.com/assets/features/galaxy/galaxy-f49da3cdc301163001efb549cec16a8f4dffb4d9894c51cfadc85c9e62f857c6.webp) Geolocation ## Geolocation Testing on Samsung Galaxy Perform geolocation testing in various regions across the world. Test Samsung Galaxy Geo Targeting, Geo Blocking and Geo Localization in 10 countries, including Australia, Belgium, France, Germany, United Kingdom, United States and more. Screenshots ## Responsive Testing On Samsung Galaxy Choose between various Samsung Galaxy devices with different screen sizes to perform responsive testing. Rotate the device for landscape and portrait mode testing. [Get started free](https://testingbot.com/users/sign_up) ![Responsive Testing On Samsung Galaxy](https://testingbot.com/assets/features/iphone/iphones-0b63ad1776aeba250ec3267b812d4444b10d5a814d701332120e465724288789.webp) ![Appium Cloud Testing](https://testingbot.com/assets/integrations/appium-75e88eb18ca3b2ce63d641547ce06398c8ecd971ed17187c9134c8d205465f18.svg) Appium Testing ## Automated Android Testing with Appium Use [Appium](https://testingbot.com/features/automation/appium) to connect to our grid of physical Samsung Galaxy devices and run automated mobile tests against your website or mobile app. ### Real Devices Run your Appium tests on physical mobile devices, without maintaining your own in-house device lab. ### Geolocation Testing Run Appium tests with TestingBot's built-in geo-location testing feature. Choose from up to 20 regions around the globe. ### Reliable Service Test on a reliable platform, with zero test flakiness. Ship your website and mobile app with confidence. ![TestingBot Tunnel](https://testingbot.com/assets/tunnel-diagram-5f56f4b5abdaac97336aed48dd92d9cb36acc72548052521f3581b18b88bd9ad.png) Secure Tunnel ## Local Android Testing Use our [secure tunnel](https://testingbot.com/support/tunnel) to quickly and easily test your staging website on a Chrome browser version running on Android. Once you download and start our tunnel, you can immediately test your webapps running on your computer or internal network on any Samsung Galaxy device in our cloud, straight from your browser. [Read more](https://testingbot.com/support/tunnel) FAQ ## Frequently Asked Questions ### Why should I test on Samsung Galaxy devices? Samsung Galaxy Devices are very popular with close to 28% of the global market share. In some countries, such as Brazil or India, the market share is close to 40%. It's important to make sure your website and mobile apps work on these devices. TestingBot allows you to test on the most popular Samsung Galaxy phones and tablets. ### Should I use a Samsung Galaxy Emulator? Emulators do not mimic the full user experience, they are laggy and have subtle differences. Google recommends testing your apps on real devices, before submitting to the Play Store. Emulators do not provide key features such as placing phone calls or advanced camera usage. ### Why should I use TestingBot to test on Samsung Galaxy? TestingBot provides physical Samsung devices, ranging from Samsung Galaxy S8 to S23 and Samsung Galaxy Tab devices. Instantly interact with a remote, physical device, via TestingBot's cloud. Test, debug and fix bugs using native developer tools. ### How can I test for compatibility on Samsung Galaxy S21? Instead of purchasing a S21 or setting up an emulator, you can simply connect to the TestingBot remote device grid. Developers and QA teams can use TestingBot's online devices. Test on devices such as Samsung Galaxy S8, S10, S20, S21, S23 and more. ### Can I test Chrome on Android? All Android devices in the TestingBot cloud come equipped with the default (Chrome) browser. Our physical devices are not rooted and come with Google Play Store and Chrome. ### More reasons to love TestingBot ### 24/7 support Got questions? Ask in the 24/7 in-app customer [chat support](https://testingbot.com#) or [send us an email](https://testingbot.com/contact/new). We are here to help you! TestingBot Support Hey 👋 How can we help? I need support ### Trusted by over 14,000 teams 6M+ Tests 120k+ Users 400+ Enterprises 106 Countries [Request a demo](https://testingbot.com/demo) ### Developer Documentation Everything you need to integrate TestingBot into your workflow. Browse guides, API references and SDKs for web and mobile testing. - [Quickstart tutorials for Selenium](https://testingbot.com/support/web-automate/selenium) - [Appium Examples](https://testingbot.com/support/app-automate/appium) - [Integrations](https://testingbot.com/support/integrations) - [List of browsers & devices](https://testingbot.com/support/web-automate/browsers) [Explore Documentation](https://testingbot.com/support) ### Enterprise-grade Security Star level 1 Certified GDPR Compliant SAML SSO Single Sign-On 99.99% Uptime SLA [Visit TestingBot Trust Center](https://trust.testingbot.com/) Get Started ### Ready to start Galaxy Testing? Start testing on real Galaxy devices in minutes. No credit card required. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/support # Documentation Welcome to the TestingBot Developer Platform! The TestingBot platform allows you to test your websites and apps on hundreds of browsers & devices. ### [Automated Web Testing](https://testingbot.com/support/web-automate/selenium/nodejs) Get started with automated testing of websites. - [![Selenium](https://testingbot.com/assets/support/selenium.svg)Selenium](https://testingbot.com/support/web-automate/selenium) - [![Cypress](https://testingbot.com/assets/support/cypress.svg)Cypress](https://testingbot.com/support/web-automate/cypress) - [![Puppeteer](https://testingbot.com/assets/support/puppeteer.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer) - [![Playwright](https://testingbot.com/assets/support/playwright.svg)Playwright](https://testingbot.com/support/web-automate/playwright) * * * [List of remote browsers (+5000)](https://testingbot.com/support/web-automate/browsers) ### [Automated App Testing](https://testingbot.com/support/app-automate) Run automated tests against native mobile apps. - [![Appium](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium) - [![Espresso](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)Espresso](https://testingbot.com/support/app-automate/espresso) - [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)XCUITest](https://testingbot.com/support/app-automate/xcuitest) - [![Maestro](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)Maestro](https://testingbot.com/support/app-automate/maestro) * * * [List of physical devices](https://testingbot.com/support/app-automate/devices) ### [AI Testing](https://testingbot.com/support/ai)NEW Use AI to test. Connect remote browsers with LLM frameworks. - [Codeless tests with AI](https://testingbot.com/support/ai/codeless) - [Generate tests with LLM](https://testingbot.com/support/ai/chat) - [Test Recorder](https://testingbot.com/support/web-automate/codeless-automation/add-test) - [Functions](https://testingbot.com/support/functions) * * * [AI Integrations](https://testingbot.com/support/ai/integrations) ### Manual Web & App Testing Control a remote browser or device. - [Manual Web Testing](https://testingbot.com/support/web-live) - [Manual App Testing](https://testingbot.com/support/app-live) ### [Visual Website Testing](https://testingbot.com/support/visual-testing) Capture and compare screenshots. - [Automated Visual Testing](https://testingbot.com/support/visual-testing/automated) - [Codeless Visual Testing](https://testingbot.com/support/visual-testing/codeless) ### [Accessibility Web Testing](https://testingbot.com/support/accessibility) Test the accessibility of your URLs. - [Selenium + Accessibility](https://testingbot.com/support/accessibility/web/selenium) - [Scheduled Testing](https://testingbot.com/support/accessibility/web/scheduled) ## More resources ### [Guides & articles](https://testingbot.com/support/web-automate/selenium/nodejs) Learn more about TestingBot - [Top Web Development Tools in 2025](https://testingbot.com/resources/articles/web-development-tools) - [Most popular Screen Resolutions](https://testingbot.com/resources/articles/common-screen-resolutions) - [Selenium Python Tutorial](https://testingbot.com/resources/articles/python-selenium-web-automation-test) - [How to Change Browser Settings](https://testingbot.com/resources/articles/how-to-change-browser-settings) ### [TestingBot Platform](https://testingbot.com/support/app-automate) Learn more about the TestingBot platform. - [Status](https://status.testingbot.com) - [Configuration](https://testingbot.com/support/other/configuration) - [Trust Center](https://trust.testingbot.com) - Need help? [Contact Support](https://testingbot.com/contact/new) or use the [TestingBot Slack Workspace](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) - Check out our [changelog.](https://testingbot.com/product-updates) - Questions? [Schedule a demo.](https://testingbot.com/demo) - LLM? [Read llms.txt.](https://testingbot.com/llms.txt) --- URL: https://testingbot.com/support/analytics # Analytics TestingBot provides a suite of graphs and data tables to help you understand and improve the quality of your tests. - [Guide](https://testingbot.com/support/analytics/guide) - [Test Insights](https://testingbot.com/support/analytics/insights) - [Build Analytics](https://testingbot.com/support/analytics/builds) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/analytics/insights # Test Insights The Test Insights page provides, for each test you run on TestingBot, a scatter-plot visualization. This is a great way to visualize how your test is doing with regards to **performance** and **flakiness** over time. You'll get a visual overview of how the test has been running the previous weeks and months. Discover trends and outliers and find out how robust your test has run over time. The only prerequisite is that you've [annotated your webdriver sessions with the same name](https://testingbot.com/support/api#updatetest). Only then can we track how your test has been performing over time. ## Viewing Test Insights for a test In our [member dashboard](https://testingbot.com/members), navigate to the test details page of a test session. Click the `test name` on the `test details page` to open the Test Insights page for this test. **Important:** Only tests that have a name (and not `unnamed test...`) will show this option. ## Reading the Scatter Plot Visualization On this page you'll find a scatter plot with some additional metrics on top of the graph. Performance metrics include: - **Total Runs:** how many times you've run this test in the past. - **Total Failures:** how many times in the past did this test fail. - **Fastest Runtime:** how many seconds did the fastest run of this test take in the past. - **Slowest Runtime:** how many seconds was the slowest execution of this test in the past. ![Test Scatter Plot](https://testingbot.com/assets/support/analytics/insights-db60d9fc6ca0cc9c4f0c7294d337547c1db38786b4036fa302faf486f4cf6131.png) The example graph above shows what to expect from the Test Insights page. This is a scatter plot, where each dot represents a session with the identical name. The `X-axis` indicates a time range (which you can specify in the filter below the graph). The `Y-axis` indicates the duration (in seconds) of each test. The color of the dot indicates if the test passed (green), failed (red) or unknown (gray). TestingBot does not know your test status by default, you need to [annotate your tests with a success parameter](https://testingbot.com/support/api#updatetest). ## Interpreting results You can pan the graph to zoom in or out, and use the filter below the graph to change the time range. Clicking a dot will navigate to the test details page of that test session. The example above shows a very consistent graph, with a high pass rate and a couple of (failed) outliers. Other graphs may show a different story. For example, a flaky test will show a scatter plot with `failures` on first run and `passes` on re-runs. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/analytics/builds # Test Builds Test Builds are group of tests. This term is usually used in a CI/CD context. Whenever you want to deploy to production, you'll run a group of tests to verify the build. It is possible to [annotate your Selenium WebDriver tests with a build identifier](https://testingbot.com/support/web-automate/selenium/test-options#build). When TestingBot sees a `build identifier` in the desired capabilities of your test, we will add the test to the group you specified. ## Build Graph In our [member dashboard](https://testingbot.com/members), navigate to the build overview page and click a build name. You will see a page with a pie-chart of the build's success rate and a table with all tests included in this build. ![Build Analytics](https://testingbot.com/assets/support/analytics/build-d16f497f14b60b08e5a47b0ab2b59b4080a905946fd5e95fc52b6131955b812b.png) Click the `green` or `red` slice of the pie-chart to see a list of `passed` or `failed` tests. ## Build Efficiency For each build, we calculate an `efficiency percentage`. This number indicates how well your test runner has been using `parallelization` to shorten the total test duration of the test build. One of the advantages of using TestingBot is its `concurrency`: run multiple tests simultaneously to drastically shorten the total time required to run all your tests. For example: - Running 10 tests in the build `sequentially`, where each test takes 30 seconds, would result in a total test build duration of **300 seconds**. - Running these 10 tests in `parallel`, where each test still takes 30 seconds, would result in a total test build duration of **30 seconds**. The `efficiency percentage` is calculated as a percentage. It is based on how long the build took to run, compared to the duration of the longest test in the build. Efficiency Percentage | Degree of Parallelization | Description || 0%-20% | Sequential | All your tests have been running sequentially. Consider speeding up your build time with parallelization. | | 20%-90% | Semi-Parallel | Some of your tests are running in parallel. There is still room for improvement: add more parallelization to run all tests in your build simultaneously. | | 90%-100% | Full Parallel | You are taking full advantage of parallelization and your test build is optimised for the fastest build time. | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/analytics/guide # Analytics TestingBot provides detailed analytics about your test sessions. We provide you with graphs and metrics, allowing you to: - Reduce time spent analyzing test results - Locate bottlenecks in your test performance - See for which browsers and platforms your tests are flaky and more prone to failure - Determine if a build is release quality ## Filters Our analytics filters allow you to drill down on your metrics and visualize the information you need. ![Analytics Filter](https://testingbot.com/assets/support/analytics/filter-90b35e678a8aa60b19d46a1f1edd49d4f6c01c8b069da8b4a2b5e570a32a8e9e.png) You can filter on several things, including: - Start/End time of the test - Browser/Device - Status (Passed, Failed, Unknown) - Group by date/status - Filter by [Build](https://testingbot.com/support/web-automate/selenium/test-options#build) - Filter by groups: only show tests that have a [group (tag)](https://testingbot.com/support/web-automate/selenium/test-options#grouping) included in their desired capability. - Filter by [team member](https://testingbot.com/support/team/sub-accounts) ## Graphs ![Analytics Graphs](https://testingbot.com/assets/support/analytics/graph-07d678a57d51edf51c1fafa266ddfef3bb4264ba6dccf334d5b372b0a35954b4.png) One of the first graphs you'll see is the graph above. This Column Chart shows an overview of the pass/fail rate for all your tests, grouped by day, for the last 31 days. Each column represents a day, and may include: - **Passed/Success:** all tests marked as passed - **Failure:** all tests marked as failed - **Unknown:** we don't know the status about this test. Please use our API to mark this test as passed/failed. Using the filter, you can change the date range and filter by various things (see above). If you click part of the graph, you'll navigate to an overview of all tests for that specific part. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing # Billing - [Payment Options](https://testingbot.com/support/billing/payment-options) - [Charges](https://testingbot.com/support/billing/charges) - [Upgrading](https://testingbot.com/support/billing/upgrading) - [Invoices](https://testingbot.com/support/billing/invoices) - [Cancel](https://testingbot.com/support/billing/cancel) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing/payment-options # Payment Options You can see the list of our prices on our [pricing page](https://testingbot.com/pricing). We accept the following payment options: - Credit card payment - PayPal - Wire Transfer ([contact us for wire details](https://testingbot.com/contact/new)) - [AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-yv6ds4mf77fao) TestingBot is PCI compliant. Please view our [SAQ A](https://testingbot.com/pci.pdf). ## Credit Card ![supported credit cards](https://testingbot.com/assets/cards-1c130150c727d3ba2045f3249ed5e069c1f42ccc17cb858689a41a1ccb7411bf.png) Billing occurs as a subscription and is handled by Stripe.com. ![Stripe Logo](https://testingbot.com/assets/stripe-7c2d0c43d09cb95597fb1402e2e35ac340f158502298ed5dfb4234ecf2c4e993.png) All payments happen on a HTTPS secured page. **Your payment data is never stored or logged on our website.** Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing/charges # Charges Billing occurs as a monthly subscription. This means that every month your account will be recharged with testing minutes. How many test minutes are added depends on the subscription you choose. You can see the various subscriptions on our [pricing page](https://testingbot.com/pricing). ## What if I use more than the provided test minutes? You will no longer be able to run your tests until the end of the month. Please consider upgrading to a plan with more capacity. **We will never automatically re-charge your subscription for extra minutes, no hidden costs.** ## When will I be billed? You will be billed on the same day of each month. If you started your subscription on the 11th day, then you will be charged the 11th day the next month. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing/upgrading # Upgrading subscription At any time you can [upgrade your current subscription](https://testingbot.com/pricing). You will not lose your remaining testing minutes for that month. Minutes will be transferred over immediately when you upgrade your plan. The number of simultaneous VMs allowed will be automatically increased after your upgrade. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing/invoices # Invoices We provide invoices for all customers with an active subscription. You can find monthly/yearly invoices (depending on the subscription) in our member area: [Your Account \> Invoices](https://testingbot.com/members/invoices). You can see the invoices in HTML format or download as PDF. If you are a sub-account in a team account, you will not be able to see the invoices. Only parent accounts or standalone accounts can see invoices. ## Changing Billing Details To change the billing details (Company name, address, VAT number, ...) please go to [Your Account](https://testingbot.com/members/user/edit) and fill in the form under "Edit your account details". When you update your billing details, the invoices will automatically be updated. Simply download the updated invoice. ## VAT number If your company is located in Europe, please provide your VAT number in the form ["Edit your account details"](https://testingbot.com/members/user/edit). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/billing/cancel # Cancel Subscription At any time you can choose to stop your subscription. Simply go to [Your Account \> Invoices](https://testingbot.com/members/invoices) and click "cancel subscription". Sorry to see you cancel your subscription. Please [let us know](https://testingbot.com/contact/new) how we can improve our service. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/parallel-calculator # Parallel Testing Calculator Parallel testing allows you to run multiple tests simultaneously across various browsers, devices, and OS combinations. This approach enables more tests to be run at once, significantly decreasing overall testing time. Faster build times mean faster releases and less time spent waiting for builds to complete. Use this calculator to understand how parallel testing can help you achieve your test coverage and build execution time goals. Simply input your current testing setup and desired build time to calculate the optimal number of parallel tests needed. | Team | Current State | Desired Future State | Recommendation | | --- | --- | --- | --- | | # of Browsers and/or Devices (Current) | # of Parallel Tests | Build Time (hours) | # of Browsers and/or Devices (Desired) | Build Speed | | --- | --- | --- | --- | --- | | Team 1 | | | | | Select...Supersonic (15m)Fast (30m)Basic (2h)Custom | - | | + Add Team | Total Recommendation: - | Calculate Save & Share Use this URL to view & share these results: Copy ### Understanding the Calculator # of Browsers and/or DevicesThe number of unique desktop browser and/or mobile device combinations to test. # of Parallel TestsThe number of parallel tests you are currently running. Build TimeTime taken for your entire build to complete. --- URL: https://testingbot.com/support/team # TestingBot Team Management TestingBot provides team accounts, allowing you to share test results with your colleagues. - [Account Settings](https://testingbot.com/support/team/account) - [Team & Sub-Accounts](https://testingbot.com/support/team/sub-accounts) - [Audit Logs](https://testingbot.com/support/team/audit-logs) - [2FA](https://testingbot.com/support/team/2fa) - [SSO](https://testingbot.com/support/team/sso) - [Microsoft Entra](https://testingbot.com/support/team/sso/microsoft-entra) - [Okta](https://testingbot.com/support/team/sso/okta) --- URL: https://testingbot.com/support/team/sub-accounts # Managing Sub-Accounts Sub-accounts are accounts that can be linked to your account. They're a great way to share your subscription and test results with your team members. - Everyone in the same group can see each other's tests. - Each sub-account has its own login credentials to log into our TestingBot member dashboard, and they have their own key/secret credentials to run tests on our Selenium grid. A sub-account can create/run/delete tests, see test results and interact with the member dashboard. The things **sub-accounts can't do** : - Access any subscription related items: payment information, invoices, accounting details, ... - Add/remove any other sub-accounts ## Adding Sub-Accounts Go to [My Account \> Add Team Members](https://testingbot.com/members/sub/new) to add a new sub-account. You can choose to either: - **Invite Someone** : create a new account with email/password combination. We'll send an activation link to this person's email address so he/she can immediately log in with the newly created sub-account. - **Add existing TestingBot User** : in case the person you'd like to add to your group already has an account on TestingBot, then simply fill in the email address they use on TestingBot. They'll receive an invite to join your group account as a sub-account. ## Modifying Sub-Accounts To remove or edit a sub-account, go to [My Account \> Team Members](https://testingbot.com/members/sub). ### Disconnecting a sub-account From there, you can **disconnect a sub-account** (clicking the red cross icon). This disconnects the sub-account from your group. The account will not be removed from our system, but it will no longer be associated with your account or other sub-accounts. ## Read-Only Sub-Accounts Making a sub-account Read-Only means the account can only view tests, not modify or remove any results from the team account. ## Permissions You can choose to create a sub-account with either **USER** permissions or **ADMIN** permissions. - **USER:** a sub-account does not have any rights to add/remove other team members to the team account. - **ADMIN:** an admin account can add/remove other users to the team account. ## Concurrency Limit The Concurrency Limit indicates how many tests a user can run simultaneously. The more tests you run concurrently, the faster you can process all your tests. By default, a sub-account will have the same amount of concurrency as the parent account (which depends on the pricing plan that the parent account is subscribed to). It is possible to change the concurrency limit per user. This way, you can for example divide the amount of concurrency you have across various team members. For example: you have an Enterprise plan with 30 parallel tests: You can assign 10 parallel tests to team member **A** , 15 to team member **B** and 5 to team member **C**. A user can not run more tests concurrently than the maximum amount assigned. If the user tries to run more tests, the tests will be queued in our system, waiting for a slot to free up. If you do not change this setting for any of the sub-accounts, then all sub-accounts will have access to the maximum amount of concurrency. Whenever this threshold is reached, extra tests for any sub-account will be queued until a slot frees up. ## Tests Overview for Sub-Accounts To see a list of tests created by a sub-account, click "Tests run by this user". The list contains tests run by this sub-account (with their own key/secret). ## Team Activity Log Team admins are able to see an overview of the actions performed by their team members in the Team Activity Log overview page. On the Team Management page, please click the **Activity Log** tab to open the overview. In this activity log we will show the following events for your team members: - A user from your team logged in - A user from your team logged out - A user was added to your team - A user was removed from your team - A team member's user level was upgraded or downgraded Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/2fa # Why Two-Factor-Authentication (2FA) Two Factor Authentication allows you to add an extra layer of security to your account. By supplying us with your mobile phone number, we can send you an extra authentication token every time you managed to successfully log in with your TestingBot username and password. The token you receive on your mobile device will then have to be entered after logging in on TestingBot in order to access your TestingBot account. This way there's an extra security layer; if your credentials ever got compromised the attacker would also need access to your mobile device in order to log in on TestingBot. ## Enable 2FA Log into your TestingBot account and go to [My Account](https://testingbot.com/members/user/edit). At the bottom of this page, you will find an [enable 2FA](https://testingbot.com/members/2fa/enable) link. To enable the 2FA, fill in the phone number of your mobile device. Make sure to enter the country code as well. For example, for a US mobile device, make sure the number starts with `+1` Once that's done, we'll send a verification code to your mobile device through SMS. Fill in this verification code on the [enable 2FA](https://testingbot.com/members/2fa/enable) page to complete this process. Once this process has been completed, the next time you log in you will be required to enter the verification code we'll send to you after logging in with email/password. ## Google Authenticator It's possible to use [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en) to generate the 2FA token required to log in. Simply scan the QR code to start generating these tokens. The next time you'll log in, you can use the token provided by Google Authenticator to log in via 2FA. ## Disabling 2FA Log into your TestingBot account and go to [My Account](https://testingbot.com/members/user/edit). At the bottom of this page, you will find a disable 2FA link. Click this link to disable 2FA. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/account # How to update my account details? You can update your account details (email, first name, last name) by going to [Members \> Account](https://testingbot.com/members/user/edit). In the form "Edit your account details" you can update your personal details. ## Resetting Security Tokens You can find your Security Tokens (`Key` + `Secret`) by going to [Members \> Manage Credentials](https://testingbot.com/members/user/security). These two identifiers are necessary to authenticate to our Selenium grid. It is possible to reset these security tokens by clicking the "Generate new keys" link. **Caution:** resetting these tokens means your existing tests with older key/secret credentials will stop running. ## Change Password You can change your current password by logging into TestingBot and going to [Members \> Security](https://testingbot.com/members/user/edit). Click "Change Password". You will be asked to fill in your current password and a new password. ## Active Sessions On the [Security page](https://testingbot.com/members/user/security) you can find an overview of the active sessions for your account. Each entry contains the logged-in IP address, device name and last active time. You can sign out of individual sessions, or sign out everywhere. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/audit-logs # TestingBot Audit Logs Audit logs provide a comprehensive record of all activities performed by team members in your TestingBot organization. These logs help you maintain security, ensure compliance and monitor user behavior across your testing infrastructure. Only organization administrators can view and manage audit logs. Audit logs are retained for a maximum of 60 days. ## How to Access Audit Logs To view your organization's audit logs: 1. Log into your TestingBot account 2. Navigate to [Members → Team Activity](https://testingbot.com/members/sub/activity) 3. View the comprehensive activity log for your organization The audit log interface provides filtering options to help you find specific events by date range, event type or team member. ## Event Types TestingBot tracks the following types of activities in your audit logs: | Category | Event | Description | | --- | --- | --- | | Authentication | Login | User successfully logged into the TestingBot platform | | Authentication | Logout | User logged out of the TestingBot platform | | Account Management | Add Account | New team member was added to the organization | | Account Management | Remove Account | Team member was removed from the organization | | Account Management | Profile Update | User updated their profile information (name, email, etc.) | | Plan & Configuration | Upgrade Level | Account plan was upgraded to a higher tier | | Plan & Configuration | Downgrade Level | Account plan was downgraded to a lower tier | | Plan & Configuration | Max Parallel Changed | Maximum parallel test sessions limit was modified | | Plan & Configuration | Max Parallel Device Changed | Maximum parallel device sessions limit was modified | | Security | Password Changed | User changed their account password | | Security | Change Keys | User regenerated their API access keys (Key + Secret) | | Security | 2FA Enabled | Two-factor authentication was enabled for the account | | Security | 2FA Disabled | Two-factor authentication was disabled for the account | | Team Invitations | Invite Sent | Team invitation was sent to a new member | | Team Invitations | Invite Accepted | Team member accepted their invitation and joined the organization | | Team Invitations | Invite Denied | Team invitation was declined or rejected | ## Filtering and Searching The audit log interface provides several filtering options to help you find specific events: - **Filter by Event Type:** Select specific event types to view only those activities - **Filter by User:** Show activities performed by a specific team member - **Filter by Date Range:** Specify a custom date range to narrow down the results ## Data Retention and Export You can export all audit logs in `.CSV` format. For compliance and record-keeping purposes, we recommend regularly exporting your audit logs if you need to maintain historical records beyond the 60-day retention period. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/sso # Setting Up Single Sign On (SSO) TestingBot supports Identity Provider (IdP)-initiated and Service Provider (SP)-initiated Single Sign-On (SSO) via the SAML 2.0 protocol. This allows your authorized employees to access TestingBot in a moderated fashion, as an alternative to using passwords. To start using SSO, please make sure you have an [Identity Provider (IdP)](https://testingbot.com#idp) set up. ## Setting Up Identity Provider TestingBot provides preconfigured SAML applications for a selection of Identity Providers (IdPs). These applications allow you to integrate SSO with TestingBot in a very easy way. Below is a list of SAML applications available: - [Microsoft Entra](https://testingbot.com/support/team/sso/microsoft-entra) - [Okta](https://testingbot.com/support/team/sso/okta) To set up a custom Identity Provider, such as Salesforce, ForgeRock, Auth0 or others, please follow the steps below. 1. Retrieve the [SAML metadata](https://testingbot.com/users/saml/metadata) from TestingBot. 2. Log in to your identity provider's administrator panel. 3. If your IdP does not allow you to upload the metadata file, you can set up the integration manually. 4. Export SAML metadata of your newly created SAML application. Please [email it to us](https://testingbot.com/contact/new) so that we can set up the connection for you. ## Service Provider SAML Requirements Below is a list of settings that are required by the TestingBot Service Provider: Setting Name | Value || Entity ID | `https://testingbot.com/users/saml/metadata` | | Assertion Consumer Service (ACS URL, Reply URL) | `https://testingbot.com/users/saml/auth` | | Name ID (Unique User Identifier) | `email` | | Name ID format/policy | `urn:oasis:names:tc:SAML:2.0:nameid-format:transient ` | | Binding | `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST ` | | Idp Cert Fingerprint Algorithm | `http://www.w3.org/2000/09/xmldsig#sha256 ` | | Login URL | `https://testingbot.com/users/sign_in` | ### SAML Claims TestingBot Service Provider supports the following SAML custom claims: - `email` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/email` - `first_name` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname` - `last_name` - `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` ## SSO Options We provide the following options with Single Sign On: #### Just-In-Time (JIT) Provisioning If a user from your organization logs in through SSO, we can automatically create an account for this user on TestingBot, which will be associated to your team. Each user will be able to see the tests created by other members of your organization. If this setting is disabled, users that are not yet registered with TestingBot will not be able to use TestingBot. #### Enforce SSO (Big Bang) When this setting is enabled, users in your organization must log in through SSO. All other authentication methods will not be allowed. #### Email verification New users logging in through SAML for the first time will automatically have their account (and email address) verified. #### Logout TestingBot supports both SP-Initiated logout and IdP-initiated logout. If you'd like to set up SP-initiated logout, please [contact us](https://testingbot.com/contact/new) with your IdP SLO endpoint. ## Unsupported Features We currently do not provide support for these features: - SCIM (System for Cross-domain Identity Management) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/sso/microsoft-entra # Setting up SSO with Microsoft Entra TestingBot has created a SAML app in Microsoft Entra which you can use to easily enable SSO with Entra and TestingBot. 1. Go to **Browse Microsoft Entra Gallery** and search for **TestingBot**. 2. Click the TestingBot app to go to the detail page. Click the **Create** button to add the app. 3. In the **Credentials Details** section, make sure that the value for **Application username format** is a valid email address. The default format for Okta username is an email address, unless it has been changed in the Okta Admin Console. 4. Click **Single Sign on** in the Manage section, then select **SAML** as the single sign-on method. 5. Make sure you fill in the required information in the **Basic SAML Configuration** , such as the **Identifier (Identity ID)**. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/team/sso/okta # Setting up SSO in Okta TestingBot has created a SAML app in Okta which you can install to easily enable SSO with Okta and TestingBot. 1. Log in to the **Okta administrator panel** , go to **Applications** and search for TestingBot in the **Browse App Integration Catalog**. 2. Click the TestingBot app to go to the detail page. Click the **Add Integration** button to add the TestingBot app. 3. Change the name of the application to your liking, or leave it as TestingBot, then click **Done**. 4. You can now assign one or more users or groups to use the TestingBot application. 5. Click the **Sign On** tab. 6. In the **Credentials Details** section, make sure that the value for **Application username format** is a valid email address. The default format for Okta username is an email address, unless it has been changed in the Okta Admin Console. 7. In the **SAML Signing Certificates** section, click **Actions** , and then **View IdP metadata**. Please [send the metadata to TestingBot](https://testingbot.com/contact/new). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/configuration # TestingBot Configuration TestingBot provides a distributed grid of browsers and devices. Connect your Selenium, Appium, Puppeteer, Playwright, Cypress, XCUITest and Espresso tests to this cloud-based grid. Currently we use: **Selenium 2.53.1** for JWP protocol and **Selenium 3.141.59** for W3C protocol. ## TestingBot Status Please subscribe to [the TestingBot statuspage](https://status.testingbot.com/) or follow us on [Twitter @testingbotops](https://twitter.com/testingbot_ops) for status updates regarding our service. [![Uptime Report for Website: Last 30 days](https://share.pingdom.com/banners/3eeaadba "Uptime Report for Website: Last 30 days")](http://stats.pingdom.com/kwiiczwo3ltc)[![Uptime Report for Selenium Grid: Last 30 days](https://share.pingdom.com/banners/05c747d9 "Uptime Report for Selenium Grid: Last 30 days")](http://stats.pingdom.com/kwiiczwo3ltc) ## TestingBot IP Ranges Below you will find an up-to-date list of the TestingBot IP ranges used during testing. - 109.68.162.161 - 109.68.162.165 - 78.20.187.211 - 162.55.135.22 - 95.217.83.184 - 95.216.39.110 - 65.21.76.124 - 95.216.229.109 - 142.132.137.7 You can also fetch this up-to-date list from the [TestingBot REST-API](https://testingbot.com/support/api#ipranges). ### Geolocation IP ranges TestingBot provides [geolocation testing](https://testingbot.com/support/web-automate/selenium/test-options#geo), allowing you to test from various geographical places around the world. Below are the IP addresses we use for this. - **AU** Australia: `35.213.216.75` - **BH** Bahrain: `157.175.63.174` - **BE** Belgium: `109.68.162.161` - **BR** Brazil: `35.215.244.91` - **CA** Canada: `34.47.9.124` - **CL** Chile: `34.176.132.166` - **FR** France: `15.236.216.234` - **DE** Germany: `188.245.92.209` - **IN** India: `35.207.203.231` - **IT** Italy: `15.161.57.62` - **JP** Japan: `35.213.44.184` - **NO** Norway: `51.120.9.213` - **SG** Singapore: `18.138.255.42` - **ZA** South Africa: `13.245.163.253` - **SE** Sweden: `16.171.19.152` - **CH** Switzerland: `34.65.52.54` - **AE** United Arab Emirates: `20.174.25.155` - **GB** United Kingdom: `35.214.33.251` - **US** United States: `178.156.132.19` ## Selenium Grid configuration | Key | Value | | --- | --- | | Selenium Version | Selenium 2.53.1 [(change)](https://testingbot.com/support/web-automate/selenium/test-options#seleniumversion) for JWP protocol Selenium 3.141.59 [(change)](https://testingbot.com/support/web-automate/selenium/test-options#seleniumversion) for W3C protocol | | HUB URI | hub.testingbot.com | | HUB Port | 4444, 80 or 443 (HTTPS/SSL) | | Default Idle Timeout | 130 seconds [(change)](https://testingbot.com/support/web-automate/selenium/test-options#idletimeout) | | Default Screen Resolution | 1280x1024 [(change)](https://testingbot.com/support/web-automate/selenium/test-options#screenresolution) | ## Appium Grid configuration | Key | Value | | --- | --- | | Appium Version | Latest compatible version according to the specified device and version. [(change)](https://testingbot.com/support/app-automate/appium/options#appiumVersion). | | HUB URI | hub.testingbot.com | | HUB Port | 4444, 80 or 443 (HTTPS/SSL) | | Default Idle Timeout | 130 seconds [(change)](https://testingbot.com/support/web-automate/selenium/test-options#idletimeout) | ## Puppeteer/Playwright configuration | Key | Value | | --- | --- | | Playwright/Puppeteer version | TestingBot uses the same Playwright version as the one you are using, ensuring full compatibility. | | HUB URI | hub.testingbot.com | | HUB Port | 4444, 80 or 443 (HTTPS/SSL) | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/sharing ### Available Topics: - [Link to a Test](https://testingbot.com#linktest) - [Link to a Build](https://testingbot.com#linkbuild) - [Embed Test Info](https://testingbot.com#embedinfo) - [Embed Test Video](https://testingbot.com#embedvideo) # Sharing Tests Below are various ways to share, embed or link to a test or build on TestingBot. To share, view or link to a test, it is important to know its `sessionId`. Selenium and Appium will return a `sessionId` when a client starts a new session. This sesssionId is a unique identifier and changes per test. It is stored as a member variable of the instantiated Driver object. Most of the time it is named `sessionId` or `session_id`, depending on the client you are using. ## Link to a Test You can easily share a single test result with someone in a safe way, without the other person needing an account. To share a test result, you'll need to create the following url: https://testingbot.com/tests/ **sessionId**?auth= **authentication-hash** The authentication hash is created with md5 in the following format: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}:#{session_id}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET:session_id"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:$session_id"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:#{session_id}".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"))); An example link would then be: https://testingbot.com/tests/9jf392fj3j2f3ojid8?auth=230i439uf3fojf ## Link to a Video You can easily share a video of a specific test, please see the example below: To build the URL with the correct authentication hash, the URL should be structured like this: https://testingbot.com/tests/ **sessionId.mp4**?auth= **authentication-hash** The authentication hash is created with MD5 in the following format: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}:#{session_id}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET:session_id"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:$session_id"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:#{session_id}".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"))); An example link would then be: https://testingbot.com/tests/9jf392fj3j2f3ojid8.mp4?auth=230i439uf3fojf ## Link to a Build With TestingBot, it is possible to group several tests under one build identifier. In our member area, you can then see all the tests grouped by builds. To link to a build overview, please see this example: `https://testingbot.com/builds/YOUR_TESTINGBOT_KEY?auth=authentication-hash` To generate the authentication-hash, you must concatenate user key and user secret, then generate the MD5 hash: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET"))); To link directly to a build, please see this example: `https://testingbot.com/builds/YOUR_TESTINGBOT_KEY/build-identifier?auth=authentication-hash` To generate the authentication-hash, you must concatenate user key, user secret and build-identifier, then generate the MD5 hash: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}:#{build_identifier}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET:build_identifier"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:$build_identifier"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:#{build_identifier}".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET:build_identifier").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET:build_identifier"))); The build-identifier is the custom string you can [send as an option to group several tests.](https://testingbot.com/support/web-automate/selenium/test-options#build) ## Embed Test Info You can embed a test page in any CI detail page, test report or custom website. Please see the example below. You add a SCRIPT tag in your page which links to the test. Replace sessionId with the correct sessionId of the test. To generate the authentication-token, you must concatenate user key, user secret and sessionId, then generate the MD5 hash: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}:#{sessionId}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:$sessionId"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:#{sessionId}".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"))); ## Embed Video Info Next to embedding test info pages, you can also embed the video of the test. This might be useful to include in test reports or on CI result pages. To generate the authentication-token, you must concatenate user key, user secret and sessionId, then generate the MD5 hash: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}:#{sessionId}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:$sessionId"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET:#{sessionId}".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET:sessionId"))); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/sikuli # Sikuli Cloud Testing Sikuli uses image recognition to identify components you want to interact with on the screen. While Selenium is limited to interacting with browsers, Sikuli can be used to interact with native GUI components (for example: Windows dialogs, Linux programs or OS-X GUI). At TestingBot, all our VMs are able to run your Sikuli scripts. ## 1. Download and Setup Sikuli To get started, please [download Sikuli](http://www.sikulix.com). Once downloaded, run the file to install Sikuli. ## 2. Create a new Sikuli script ![Sikuli script](https://testingbot.com/assets/support/sikuli_script-60b7ed26c56bb2d57ddeab1c5820dee0a5644a4b18f3b862b156ae8b0f7084c8.png) Sikuli uses image-recognition to find the components to interact with. In this example, we'll take a screenshot of a Chrome dialog asking to install a Chrome extension. ## 3. The Sikuli script As you can see on the screenshot above, you can use `wait([image], FOREVER)` to have Sikuli wait for something to appear on the screen that looks like the `[image]`. Once this happens, Sikuli will move on to the next step in the script: clicking the component it detected. ## 4. Integration with TestingBot At TestingBot, we can run your Sikuli script at the start of your Selenium WebDriver test. Simply create a zip-file with one or more of your `.sikuli` scripts inside. Then use this URL in your `DesiredCapabilities` when starting a test. This way you can run Sikuli tests in the cloud on all our [platforms](https://testingbot.com/support/web-automate/browsers). For example: DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "VISTA"); caps.setCapability("version", "9"); caps.setCapability("browserName", "internet explorer"); caps.setCapability("sikuli", "http://mywebsite.com/sikuli-scripts.zip"); This will make sure TestingBot will download your Sikuli script and run it at the start of your test. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/errors ### Possible Errors: - [Minutes Depleted](https://testingbot.com#1) - [Max Duration Exceeded](https://testingbot.com#2) - [Test Timeout](https://testingbot.com#3) - [New session cancelled before start](https://testingbot.com#4) # Errors/Failures during Testing Below is a list of various error messages and failures that might happen when running Automated Tests. ## Minutes depleted #### Description: The test failed because your account does not have enough minutes left. If your account does not have enough minutes, tests can no longer be started on TestingBot. #### How to resolve: Please [consider upgrading your account](https://testingbot.com/pricing) to make sure you have enough credits/minutes to run tests. ## Your test exceeded max duration #### Description: The test was terminated because it exceeded the maximum duration allowed. (default is 1800 seconds) #### Cause: This might be caused by several things: - Your test is too long. Consider splitting large tests into multiple smaller tests. - Tests running on TestingBot can take longer to run than they do locally - Your test is stuck in an endless loop, where your test keeps sending commands #### How to resolve: - Consider breaking up your test into smaller, atomic tests. - You can use the [maxDuration desired capability option](https://testingbot.com/support/web-automate/selenium/test-options#maxduration) to indicate to TestingBot how long you want TestingBot to wait for your test to complete. - Check for endless loops in your test ## Your test timed out #### Description: This error happens when TestingBot does not receive any new command from your Selenium script for more than 90 seconds (the default timeout duration). #### Cause: This might be caused by various things: - You forgot to add `driver.quit()` at the end of your test. To prevent your test from running forever, TestingBot will stop the test after 90 seconds to prevent this test from consuming all your minutes. - Your test script crashed, was interrupted or lost internet connectivity. - Maybe your test command needs more than 90 seconds between commands. In this case, you can specify a [different test idle timeout](https://testingbot.com/support/web-automate/selenium/test-options#idletimeout). #### How to resolve: - Make sure your test script has good internet connectivity. - Don't forget to add `driver.quit()` at the end of your test. - Specify a [different test idle timeout](https://testingbot.com/support/web-automate/selenium/test-options#idletimeout). ## New session cancelled before test start #### Description: Your test runner started a new test on TestingBot, but then closed the connection to TestingBot before TestingBot could make a new test session available. #### Cause: This might be caused by several things: - Client timeout with Android/iOS tests. Please make sure to set the connection timeout in your test runner/framework high enough, as iOS/Android simulators take a while to start up. We recommend at least 2 minutes. - You might be running too many tests at once. If you're exceeding the total number of simultaneous tests, we still queue the tests. If this queueing takes too long, your test runner might disconnect before the test started. - High waiting times at TestingBot. If our service has any issues, this error might occur. Follow us on Twitter ([@testingbotops](https://twitter.com/testingbot_ops)) and check our Status Page: [https://status.testingbot.com](https://status.testingbot.com/) #### How to resolve: - Increase the connection timeout setting in your test runner/framework. For example, for WebdriverIO, you can set `connectionRetryTimeout: 210000` - Make sure you're not exceeding the total allowed simultaneous tests, according to the TestingBot plan you're subscribed to. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/status-badges # Status Badges Status Badges help you keep track of the status of your latest test build. You can simply embed markdown code or HTML code to your project website to show the status of your most recent test build. ## Builds In order to show a status badge, you need to make sure that you're running your tests in a group, called a **build**. For example: you have a project that has a bunch of tests. After every commit you want to make sure the tests still pass. The tests you want to run are groupped in a **build**. To make sure your tests are grouped in the same build, use Selenium's Desired Capabilities. Simple pass `"build" : "build-1XXX"` in your Desired Capabilities: DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "WIN7"); caps.setCapability("browserName", "Chrome"); caps.setCapability("build", "build-1XXX"); // for example In our [member area](https://testingbot.com/members) you will then see a new build, `build-1XXX`, which will contain all the tests that ran with the same build identifier. ## Marking a build as passed/failed To mark a build as passed or failed, your test runner should be configured to send the success state of each test to TestingBot via the [TestingBot API](https://testingbot.com/support/api). - If for every test in the build we know that the test succeeded, then we'll automatically mark the build as **Passing**. - If a test failed, the build will automatically be marked as **Failed**. - If you don't send us the success state for every test in the build, then we can not know the success state of the build. In this case we show an **Unknown** state. ## Status Badge With our Status Badges, you can easily monitor the status of your most recent build. The `auth` parameter is generated by concatenating your `api key` and `api secret` with md5. Below are the different states that your badge can have: Badge | Status || TestingBotTestingBotpassingpassing | **Passing** | | TestingBotTestingBotfailedfailed | **Failure** | | TestingBotTestingBotunknownunknown | **Unknown** We don't know if this build passed or failed. Please use our [REST-API](https://testingbot.com/support/api) to send the success state of your individual tests to TestingBot. | | TestingBotTestingBoterrorerror | **Error** The link to the badge might be invalid, or you might not have any builds yet. | **Markdown:** [![TestingBot Test Status](https://testingbot.com/buildstatus/YOUR_TESTINGBOT_KEY?auth={authentication})](https://testingbot.com/builds/YOUR_TESTINGBOT_KEY?auth={authentication}) **HTML:** TestingBot Build Status [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET").digest("hex"); Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes("TESTINGBOT_KEY:TESTINGBOT_SECRET"))); ## Private Accounts To display badges, or link to builds, you need to generate an **authentication token**. To generate the authentication token, you must concatenate your TestingBot key, TestingBot secret and optionally an identifier. Finally, take the MD5 hash of the concatenated string: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET").digest("hex"); ## Open Source Accounts [Open Source](https://testingbot.com/open-source) accounts automatically have their tests and builds set to public. This means no authentication (auth parameter) is required to display badges or link to tests/builds. ## More - If you like to show status-badges of **multiple projects** , please consider creating a new user account per project. - We're also providing [browser-matrix images](https://testingbot.com/support/other/browser-matrix), displaying for which browsers your build passed/failed. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/other/browser-matrix # Browser Matrix With our Browser Matrix image you can quickly see the status for your latest test build for the various browsers/platforms. You can simply add markdown code or HTML code to your project website to show the status of your most recent test build. ## Builds In order to show a browser matrix image, you need to make sure that you're running your tests in a group, called a **build**. For example: you have a project that has a bunch of tests. After every commit you want to make sure the tests still pass. The tests you want to run are groupped in a **build**. To make sure your tests are grouped in the same build, use Selenium's Desired Capabilities. Simple pass `"build" : "build-1XXX"` in your Desired Capabilities: DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "WIN7"); caps.setCapability("browserName", "Chrome"); caps.setCapability("build", "build-1XXX"); // for example In our [member area](https://testingbot.com/members/builds) you will then see a new build, `build-1XXX`, which will contain all the tests that ran with the same build identifier. ## Marking tests passed/failed To mark tests as passed or failed, your test runner should be configured to send the success state of each test to TestingBot via the [TestingBot API](https://testingbot.com/support/api#updatetest). The browser matrix image will then show the success state for every browser/platform in your build. ## Browser Matrix Below is an example of how the browser matrix image looks like, and information on how to embed this image on your website. ![TestingBot Build Matrix](https://testingbot.com/assets/support/buildmatrix-8f49f44a625e3b4118d16079fd18239f5ed45b30ed0ba283b9e33ec980ecbc4f.png) **Markdown:** [![TestingBot Test Status](https://testingbot.com/buildmatrix/YOUR_TESTINGBOT_KEY?auth={authentication})](https://testingbot.com/builds/YOUR_TESTINGBOT_KEY?auth={authentication}) **HTML:** TestingBot Build Matrix ## Private Accounts To display the matrix image, or link to builds, you need to generate an **authentication token**. To generate the authentication token, you must concatenate your TestingBot key, TestingBot secret and optionally an identifier. Finally, take the MD5 hash of the concatenated string: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) Digest::MD5.hexdigest("#{client_key}:#{client_secret}") MessageDigest m=MessageDigest.getInstance("MD5"); String s = "TESTINGBOT_KEY:TESTINGBOT_SECRET"; m.update(s.getBytes(),0,s.length()); System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16)); echo md5("TESTINGBOT_KEY:TESTINGBOT_SECRET"); import hashlib print(hashlib.md5("TESTINGBOT_KEY:TESTINGBOT_SECRET".encode('utf-8')).hexdigest()) var crypto = require('crypto'); crypto.createHash('md5').update("TESTINGBOT_KEY:TESTINGBOT_SECRET").digest("hex"); ## Open Source Accounts [Open Source](https://testingbot.com/open-source) accounts automatically have their tests and builds set to public. This means no authentication (auth parameter) is required to display matrix images or link to tests/builds. ## More - If you like to show browser matrix images of **multiple projects** , please consider creating a new user account per project. - We're also providing [status badges](https://testingbot.com/support/other/status-badges), displaying if your build passed/failed. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/commandline # Tunnel Commandline Reference The tunnel requires both a TestingBot Key and TestingBot Secret being passed via the commandline, except in the following cases: - If you have a `.testingbot` file located in your `$HOME` directory, then the tunnel will fetch the key and secret from this file. - If you pass the following environment variables with valid key/secret: TESTINGBOT_KEY="" and TESTINGBOT_SECRET="" | -a,--auth \ | Performs Basic Authentication for specific hosts, only works with HTTP. | | -b,--nobump | Do not perform SSL bumping. | | -d,--debug | Enables debug messages. Will output request/response headers. | | -dns,--dns | Use a custom DNS server. For example: 8.8.8.8 | | --doctor | Perform sanity/health checks to detect possible misconfiguration or problems. | | --extra-headers \ | Inject extra headers in the requests the tunnel makes. | | -f,--readyfile \ | This file will be touched when the tunnel is ready for usage | | -F,--fast-fail-regexps \ | Specify domains you don't want to proxy, comma separated. | | -h,--help | Displays help text | | -i,--tunnel-identifier \ | Add an identifier to this tunnel connection. In case of multiple tunnels, specify this identifier in your desired capabilities to use this specific tunnel. | | -j,--localproxy \ | The port to launch the local proxy on (default 8087). | | -l,--logfile \ | Write logging to a file. | | --metrics-port \ | Use the specified port to access metrics. Default port 8003 | | -P,--se-port \ | The local port your Selenium test should connect to. Default port is 4445 | | -p,--hubport \ | Use this if you want to connect to port 80 on our hub instead of the default port 4444 | | --pac \ | Proxy autoconfiguration. Should be a http(s) URL | | -q,--nocache | Bypass our Caching Proxy running on our tunnel VM. | | -v,--version | Displays the current version of the Tunnel | | -w,--web \ | Point to a directory for testing. Creates a local webserver. | | -x,--noproxy | Do not start a local proxy (requires user provided proxy server on port 8087) | | -Y,--proxy \ | Specify an upstream proxy. | | -z,--proxy-userpwd \ | Username and password required to access the proxy configured with --proxy. | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/multiple # Multiple Tunnels It is possible to run up to 3 simultaneous tunnels. Either you run multiple tunnels with your own account, or you're a sub-account of a team where other colleagues have tunnels running as well. To make it possible to go through a specific tunnel, you can use the `--tunnel-identifier` option with the tunnel's commandline options. With this option you simply pass an identifier as string. For example: java -jar testingbot-tunnel.jar key secret --tunnel-identifier myTunnel Now you or your team members can use this specific tunnel in your tests: { "browserName":"firefox", "version":"latest", "platform":"WIN10", "tunnel-identifier":"myTunnel" } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/changelog # Tunnel Changelog | Version / Release Date | Changes | | --- | --- | | **4.4** Released October 2025 | - Update dependencies - Improve `--proxy` and `--proxy-userpwd` | | **4.3** Released August 2025 | - Update dependencies (Jetty + SSH lib) - Improve monitoring + retry mechanisms - Drop support for JDK 8 - Improve `--doctor` checks | | **4.0** Released December 2024 | - Update dependencies (Jetty 11) - Websocket + Server Sent Events support - Introduced `--nobump` argument to disable SSL bumping | | **3.5** Released May 2023 | - Updated dependencies - Upgraded secure connection cipher | | **3.2** Released February 2021 | - Updated dependencies | | **3.1** Released February 2020 | - Updated dependencies - Don't poll tunnel indefinitely - Built with JDK8 - Code cleanup | | **3.0** Released September 2019 | - Various minor fixes - Updated Jetty Dependencies | | **2.9** Released January 2019 | - Various minor fixes (timeouts, doctor checks, ..) - Prevent duplicate ports | | **2.8** Released June 2018 | - Fix NPE in ConnectHandler | | **2.7** Released June 2018 | - Rename jettyport option to localport - If started with --nocache, send to API for Manual Testing - Implemented upstream proxying for HTTPs via CONNECT (--proxy) - Updated pom.xml depndencies - No more hardcoded ports to listen to | | **2.6** Released April 2018 | - Remove incorrect Java version check - Remove deprecated features: --boost and --ssl - Add option to supply extra HTTP headers during requests - Add option to supply basic auth credentials for various hosts, which the tunnel will automatically use - Make the --nocache option clearer: Do not cache any HTTP requests | | **2.5** Released September 2017 | - Improved --doctor checks, check if necessary ports can be opened - Add support for --pac to set a PAC url (Proxy) for your test sessions | | **2.4** Released August 2017 | - Add --tunnel-identifier to identify different tunnels for the same account - Improved logging (formatting, log to file, debug levels, ...) - Improved handling of connection errors (re-establish connection to tunnel VM upon connection failures) - Added option where you can specify a local directory to be set up as a webserver, for example to test static files - Added an embedded statistics REST api to fetch details about the running instance, by default runs on port 8003 | | **2.3** Released October 2016 | - Add --doctor to troubleshoot misconfigurations - Debugmode will now output HTTP headers | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/examples # Examples Below you will find some examples on how to use the Tunnel. To start your Tunnel, [download the Java based Tunnel](https://testingbot.com/downloads/testingbot-tunnel.zip) and run from the commandline: java -jar testingbot-tunnel.jar key secret Below you will find an example demonstrating how to adjust your tests to use the Tunnel. **Before:** urlhub = "http://key:secret@hub.testingbot.com/wd/hub" client = Selenium::WebDriver::Remote::Http::Default.new **After:** urlhub = "http://key:secret@localhost:4445/wd/hub" client = Selenium::WebDriver::Remote::Http::Default.new Notice how we now use `localhost:4445`, which will send the test commands through the Tunnel. ## Tunnel Identifiers You can choose to use a tunnel identifier to connect to a specific tunnel. For example, launch a tunnel: java -jar testingbot-tunnel.jar key secret -i myTunnel This tunnel now has an identifier "myTunnel". You can instruct your tests to go through this specific tunnel with Desired Capabilities: { "browserName":"firefox", "version":"latest", "platform":"WIN10", "tunnel-identifier":"myTunnel" } ## Adding Extra Headers TestingBot tunnel allows you to add extra headers to the HTTP requests it will make during testing. For example, to add a custom header: java -jar testingbot-tunnel.jar key secret \ --extra-headers '{"MyOwnHeader": "HeaderValue"}' ## Upstream Proxy You can instruct TestingBot Tunnel to use a specific upstream proxy. For example, your company network requires all traffic to go through a specific proxy. Or, you'd like to do geo-location testing and want to use a proxy in a different geographical location. You can specify `-Y address:port` to indicate which proxy you'd like to use. If your proxy requires authentication, you can pass the credentials with: -z username:password For example: java -jar testingbot-tunnel.jar key secret -Y myproxy:9000 -z username:password ## Basic Authentication If you need to test a website or pages that require Basic Authentication, then you can instruct TestingBot tunnel to automatically enter the correct credentials during testing. You can specify `-a host:port:user:passwd` to indicate which credentials to use for which host (+port). If your website is not running on a specific port, you can use port 80. java -jar testingbot-tunnel.jar key secret -a mywebsite.com:80:myusername:mypassword Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/faq # Frequently Asked Questions Below is a list of questions and answers that may help you with setting up or troubleshooting TestingBot Tunnel. ## How do I use the tunnel with manual (live) testing? When you, or a team member, starts a TestingBot tunnel, all future manual tests will automatically use the latest active tunnel. Whether you do a live test on a Desktop VM, a sim/emu device or a physical device, the tunnel will automatically be used. ## My Mobile App uses Certificate Pinning. How can I add the TestingBot Tunnel CA certificate? All our VMs and mobile devices trust a TestingBot CA certificate that we generated. You can [download this CA certificate](https://testingbot.com/downloads/testingbot-ssl-bumping.crt) and add it to your app. By default, TestingBot tunnel will bump all SSL traffic to use the TestingBot CA certificate. We do this to prevent issues with self-signed certificates. If you do not wish to use this SSL bumping, you can pass `noSSLBump: true` as a capability or use the `--nocache` tunnel option. ## How many TestingBot Tunnels can I keep open simultaneously? The maximum amount of simultaneous tunnels depends on the license your account has. By default, you can run up to 2 tunnels simultaneously. ## Can I use localhost with the tunnel? You can use `localhost` on all our Desktop VMs while using TestingBot Tunnel. By default we support proxying these ports for localhost testing: `[443, 80, 8080, 3030, 3000, 3001, 3400]`. If you need additional ports, please pass an array of port numbers to either `localHttpPorts` or `localHttpsPorts` On physical mobile devices and simulators/emulators, you cannot use `localhost`. To test on mobile devices, please define a local domain name rather than localhost (127.0.0.1). You can define a local domain in your hosts file (`/etc/hosts`) on the machine where the TestingBot Tunnel program is running. For example, you can add `127.0.0.1 mywebsite` to your `/etc/hosts` file, then use `http://mywebsite` in your tests. ## Can I use websockets or SSE with the tunnel? With TestingBot Tunnel v4 and higher, it is possible to test websites or mobile apps that are using WebSockets (`ws://` and `wss://`), as well as Server-Sent Events (SSE). To get started, please make sure to pass both the `--nobump` and `--nocache` flags when using WebSockets. This is necessary because by default, TestingBot will bump SSL to get around common SSL problems (expired certificates, self-signed certificates, etc.). java -jar testingbot-tunnel.jar --nocache --nobump It is currently not possible to use localhost for `ws` and `wss` requests. To get around this, you can add a custom host in your `/etc/hosts` that points to localhost and then use that custom host instead. The Tunnel will forward the request to the machine running your tunnel endpoint and use it, as if it was localhost. 127.0.0.1 localhost 127.0.0.1 testingbot.com # add this for example, and use in ws://testingbot.com:80 ## How can I improve the performance of the tunnel? You can use the `-F,--fast-fail-regexps` option when starting the tunnel to specify a list of domains that should not be proxied at all. You can fast-fail trackers, ads and other resources that have no impact on your test or its results. This will decrease the amount of HTTP(s) requests that need to be proxied by TestingBot Tunnel. ## Can I run tests on Virtual Devices and Real Devices using the same TestingBot Tunnel? You can use the same instance of a tunnel for both virtual devices and real devices. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel/upstream-proxy # Upstream Proxy Our tunnel has built-in support to use an upstream proxy, for example a GeoIP proxy. You can test your website from various locations around the world, by utilizing HTTP proxies. java -jar testingbot-tunnel.jar --proxy --proxy-userpwd : ## More Information - TestingBot Tunnel will proxy both HTTP and HTTPs URLs to the upstream proxy (the GeoIP proxy address). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/tunnel ![Local Testing Security](https://testingbot.com/assets/features/img-tunnel-922fb736230e7833039f44855837c5d87d845f2131d055410f52462122413048.png) # TestingBot Tunnel Windows, Linux, BSD and macOS supported.[**Download Testingbot Tunnel v.4.4**](https://testingbot.com/downloads/testingbot-tunnel.zip) SHA1 Checksum: 042c23c96abcb1669fc0dda336fd6a2a615412a7 v.4.4 released October 3, 2025 (Requires Java 11 or higher) [Source code on GitHub](https://github.com/testingbot/Testingbot-Tunnel) Maven groupId: com.testingbot | artifactId: TestingBotTunnel | version: 4.4 Docker: `docker pull testingbot/tunnel` Whether you want to test your website on your local computer (localhost), on a **staging server inside your private network** or on a computer across VPN, the TestingBot Tunnel makes all of this possible in a secure and reliable way. You will no longer need to open up ports on your firewall or whitelist the TestingBot IP range to run tests on your staging environment. Below are some of the key features of the TestingBot Tunnel. - **Fast** : We cache static content on our side of the tunnel, reducing traffic and improving performance. - **Secure** : When you initiate the Tunnel, a dedicated VM server is created just for you, remaining active only for the duration of the session. - **Robust** : Full HTTP(s) + WebSockets support, built with Java for stability and performance. - **Easy** : Simple to set up and use. ## Run tests in your local environment The Tunnel makes it easy to run tests with TestingBot in your private staging environment. Whether you're testing a new feature or a major code refactor, the Tunnel allows you to easily run regression tests and ensure everything still works as expected. Just point your tests to `http://localhost` on port `4445`, instead of connecting to our grid at `https://hub.testingbot.com`. The Tunnel is a Java-based program (`.jar`) that includes a **secure HTTP(s) + WebSocket proxy**, which relays requests to the TestingBot browser and device grid. ## Optimized for Speed Setting up a Tunnel means we provision a **dedicated VM server just for you** , which takes no longer than a minute to launch. On our end, we use an accelerator that **caches static content** passing through the tunnel, speeding up the process. The Tunnel uses compression to minimize the traffic going through the tunnel. You can run multiple tunnels with a single account, allowing you to dedicate several machines on your private network to different tunnels. This setup ensures **High Availability** for your tests and services. ## Secure Tunnel All requests to and from our servers are securely routed through the Tunnel, which is built on the **SSH protocol**. A dedicated VM is provisioned just for you, and once your tests are complete, both the Tunnel and the VM server are automatically destroyed. ## Robust Tunnel The Tunnel is designed to **handle heavy traffic, even during parallel testing** , ensuring reliable performance. Built with Java, the Tunnel runs on any standard JVM. It supports HTTP, HTTPS, WebSockets, SSE, HTTP/1, HTTP/2 and HTTP/3 protocols. The standalone Tunnel application is compatible with all major operating systems: Windows, Linux, and macOS. ## Easy Setup Setting up and using the Tunnel is easy. Download the `.jar` file from our website and run it from your commandline, or use the provided Docker image (`testingbot/tunnel`). Replace the `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` with [your own key and secret](https://testingbot.com/members/user/edit). Once your Tunnel is ready, you will see the message "You may start your tests." The Tunnel creates a `~/.testingbot` file on your local system to store the `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` ## System Requirements The system requirements depend on how you are going to use the tunnel. If you intend to do parallel testing, you will need to increase the CPU and RAM of the machine running the tunnel. A machine with 4GB ram and 2 CPU cores should run the Tunnel just fine. ## Shutting down tunnel For a proper shutdown, it's recommended to exit the Tunnel gracefully. If not, the Tunnel may remain active in our system because we did not receive a shutdown command. To do a graceful exit, please use `CTRL+C` in the process window or remove the TestingBot PID file. This will trigger a graceful exit, send the shutdown command to TestingBot and clean up everything. Alternatively, you can send a `kill -SIGUSR1` signal to the `PID` of the Tunnel process. ## Tunnel Clients We have created a NodeJS based launcher which you can use in your NodeJS tests and projects: [testingbot-tunnel-launcher](https://github.com/testingbot/testingbot-tunnel-launcher) [![TestingBot Tunnel Diagram](https://testingbot.com/assets/tunnel-diagram-small-af64aa8c1e0d3558a0cc730b3b7cc827264e9af90173acb7627cff04054e1d89.jpg)](https://testingbot.com/assets/tunnel-diagram.png "How the TestingBot Tunnel works") Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/mobile # Mobile Testing TestingBot provides iOS and Android testing on both [simulators/emulators](https://testingbot.com/support/web-automate/browsers) and [real/physical devices](https://testingbot.com/support/app-automate/devices). ## Configuring capabilities TestingBot's mobile simulators and emulators can be accessed using Appium. You can use the device picker below to select the capabilities you want to use for your tests. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available devices and platforms. W3C Protocol W3C is the newest WebDriver protocol, TestingBot recommends using W3C. JSONWP JSONWP is the legacy protocol which is no longer actively maintained. JavaPythonNodeJSC#RubyPHP MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, "safari"); capabilities.setCapability(CapabilityType.BROWSER_VERSION, "18.6"); capabilities.setCapability("appium:deviceName", "iPhone 16"); capabilities.setCapability(CapabilityType.PLATFORM_NAME, "iOS");` You can configure more options by using the [Appium capabilities generator](https://testingbot.com/support/app-automate/appium/capabilities). ## Portrait/Landscape It's possible to rotate the device before and during your test. Please see these examples: **Rotate before test (iOS only):** desired_capabilities = { "orientation" : "LANDSCAPE " } # or PORTRAIT **Rotate during test:** ((AppiumDriver) driver).rotate(ScreenOrientation.LANDSCAPE); ## Specifying Appium Version TestingBot will use the most recent, compatible, Appium version according to the device, OS and version you specify. If you'd like to specify your own Appium version, you can do this with the `appiumVersion` capability. To learn more about the available Appium versions, please see our [Appium versions documentation](https://testingbot.com/support/app-automate/appium/appium-versions). [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) caps = { platformName: "iOS", deviceName: "iPhone 15", browserVersion: "17.4", browserName: 'safari', "tb:options" => { "appiumVersion" : "2.4.1" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("appiumVersion", "2.4.1"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "iOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("deviceName", "iPhone 16"); caps.setCapability("browserVersion", "18.6"); caps.setCapability("browserName", "safari"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::safari(); $capabilities->setPlatform('iOS'); $capabilities->setCapability('tb:options', array( 'appiumVersion' => "2.4.1" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'appiumVersion': "2.4.1" } chromeOpts = { 'browserName': "safari", 'platformName': "iOS", 'browserVersion': "18.6", 'deviceName': "iPhone 16", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'safari', "platformName": 'iOS', "deviceName": 'iPhone 16', "browserVersion": '18.6', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "appiumVersion": "2.4.1" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "18.6", PlatformName = "iOS", DeviceName = "iPhone 16", BrowserName = "safari", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["appiumVersion"] = "2.4.1" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ## Testing Internal/Staged Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation # Codeless Web Testing Codeless Web Automated Testing allows you to run your pre-recorded Selenium tests on the TestingBot cloud grid. - [Add a test](https://testingbot.com/support/web-automate/codeless-automation/add-test) - [Test Suites](https://testingbot.com/support/web-automate/codeless-automation/suites) - [Schedule a test](https://testingbot.com/support/web-automate/codeless-automation/schedule) - [Test alerts](https://testingbot.com/support/web-automate/codeless-automation/alerts) - [Supported commands](https://testingbot.com/support/web-automate/codeless-automation/commands) - [Variables](https://testingbot.com/support/web-automate/codeless-automation/variables) - [FAQ](https://testingbot.com/support/web-automate/codeless-automation/faq) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/add-test # Add Codeless Automation test TestingBot can create and run automated web tests against your website on regular intervals and alert you when a test fails. There are 2 options to create a codeless web automation test: - You can [record your actions](https://testingbot.com#record) with Selenium IDE, [upload the steps](https://testingbot.com#upload) and replay the steps on TestingBot. - You can choose to describe tests in natural language and have the [TestingBot AI agent](https://testingbot.com/support/ai/codeless) create and run the test for you. ## Record your actions ![Selenium IDE](https://testingbot.com/assets/support/codeless/selenium_ide-12210f05c24292c51d5f4043a24db5af420323002b5cb2ebc4ea91dff9753ef1.png) ### Installing Selenium IDE To get started, please make sure to [download the Selenium IDE](https://github.com/SeleniumHQ/selenium-ide/releases/). This is an Electron app that will run on Windows and macOS and will allow you to record and playback actions on a website and allow you to save these actions as Selenium scripts (`.side` files). You can also install the package through NPM: `npm install -g selenium-ide` ### Recording a test #### Creating a test ![Selenium IDE: add test](https://testingbot.com/assets/support/codeless/create-07a560acf47ba92d0e585b2f47f9ac754c713647f7f25f9beb43fa0d98da8ece.png) Once you have the Selenium IDE program running, you can create a new testcase by clicking the plus icon (+). Enter a name for your test. Next, open the URL you want to test in the right side of the Selenium IDE. Once the page is loaded, interact with the page. You will see new commands are added to the left sidebar, which means the IDE is recording all your actions. #### Adding verifications ![Selenium IDE: verification](https://testingbot.com/assets/support/codeless/verify-6f55be33262b647b02156c95eadfecce9b77c0712196521c3ad53fecb30abc43.png) For example, if you tap an element on the webpage, you will see a new `Click` command appear. At any given point, you can right-click an element on the page you are testing and add a verification, for example: `Record Wait For Element Present`. ### Saving test Once you've finished recording your test, you can choose to save it as a `.side` file, which is basically a JSON file that describes all the actions and verifications you added during the recording. Choose `Save Project As` and save the file. You can now [upload this file](https://testingbot.com#upload) to TestingBot and instruct TestingBot to run this test on a scheduled interval, running on the browsers & operating systems you want. ## Upload a codeless test Once you have a `.side` file, you can upload it in the [Codeless Test](https://testingbot.com/members/lab) area of TestingBot. Click the upload button in the **Import a Selenium Test** section and upload the file. Once uploaded, you will be redirected to a test configuration page. Here you can configure various options: ![Selenium IDE: steps](https://testingbot.com/assets/support/codeless/steps-ac508430b3982e357b9ba64cd7df0a9e1655eed37a795a0e87cc9495b058fcf8.png) ### Steps We will display the same steps that were recorded before. You have the option to re-order the steps, edit steps or remove steps. ### Browsers A selection of browsers & operating systems will be available to choose from. Select one or more browsers that you want to run your test on. ### Settings You can configure various settings for your test: - Schedule when the test should run; a specific time, interval, day. Or maybe every 15 minutes. You indicate how often the test will run. - Manage timeouts, screen resolution, screenshots and videos. - Daily and hourly reporting of your tests via email. - Automatically retry a failed test and if the retry succeeds, ignore the failed test. - Receive an alert via email or text message when a test fails. - Test from various geographical locations ## Run Test Now that the test has been added to TestingBot, you can choose to run it immediately. Click the **Run test** button on the top right of the edit test page, or from within the test overview page. TestingBot will run the test on the browser(s) you specified and alert you when a test failed. Each test comes with screenshots, a video and generated log files. ## API Reference You can use the [TestingBot API](https://testingbot.com/support/api) to add, edit, remove and [run Codeless Automation tests](https://testingbot.com/support/api#runlabtest). Use our [integrations](https://testingbot.com/support/integrations) to improve your workflow. For example, configure a [Slack Bot](https://testingbot.com/support/integrations/slack) to notify you when a codeless automation test failed. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/suites # Add a Test Suite In our TestLab we offer the possibility to upload test-suites (called **Projects** in Selenium IDE) generated by [Selenium IDE](https://www.selenium.dev/selenium-ide/). A test suite is a collection of tests, generated by the Selenium IDE extension. To upload the suite, please upload the exported (`.side`) file: ![Selenium IDE project](https://testingbot.com/assets/support/codeless/suite-8df25faf22e06b8749c6c03d25dab13bfc7db70fc6f448e8c129f8b1850d76da.png) ## Managing Test Suites Once uploaded to our TestLab, you will see page detailing the Project you just uploaded. It will include a list of the tests that this project contains. On this page, you can change on which browser(s) the tests should run, change alert/scheduling options and more. Changing a setting in the project affects all tests for this project. If you like to only change a single test, click through to the test edit page and make the necessary changes there. ![Selenium IDE project](https://testingbot.com/assets/support/codeless/suite-overview-d0e9677d3f9b170369bb49e9fe68746655cfd20d0ae190b8c03e05c9685dbe50.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/schedule # Schedule a test When you have [added a test](https://testingbot.com/support/web-automate/codeless-automation/add-test), you can specify when we should run the test, and how many times we should run it (interval). ![Schedule a Test](https://testingbot.com/assets/support/codeless/schedule-9a00c28724a6241167c552558a210e4776b1b5914a0202900428537b803012d7.png) You can have your test either run once, every day, every week, repeat every `..` time or use a custom CRON format. Once scheduled, you can specify when you want to be [alerted of failed tests](https://testingbot.com/support/web-automate/codeless-automation/alerts). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/alerts # Alerts When a test in Codeless Automation fails, we can notify you by sending you an email, Webhook, Push Notification or SMS/text message. You can choose to be alerted immediately, or once a day. ## Alert Types We offer 3 ways to alert you: - Email - SMS/Text message - Webhook to a URL you specify. The message you will receive will contain the URL, number of errors and an error message trace. ## Email Alerts To receive an alert via email, fill in your email address. We will send an email with the failure of the test. You can customize the error message by filling in your own text. We offer these variables to customize your error text: `%test_name%` and `%browser%`. ![Email Alerts](https://testingbot.com/assets/support/codeless/email-cb45d4d824ab7bd052575692ba60ec586173b33d83175e52e5db63bf6e00ae12.png) ## SMS Text Message Fill in your phone number (with country code) to receive an SMS message when a test fails. You can customize the error message by filling in your own text. We offer these variables to customize your error text: `%test_name%` and `%browser%`. There's also the possibility to be alerted when the test recovers. ![SMS Alerts](https://testingbot.com/assets/support/codeless/sms-1365e3a31475f9d62465031a4edbbd3c1b47c5204762b11af65bcca05fb8ff8b.png) ## Webhook We will call a URL you specify whenever a test fails. The URL needs to be publicly available, otherwise TestingBot cannot reach the URL. The URL will receive a POST request from us with the following fields: - `success` (boolean) - `job_id` (int) - internal id - `test_ids[]` (string[]) webdriver sessionIds - `errors[]` (string[]) error messages Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/commands # Supported Selenium IDE Commands Below is a list of the commands we currently support in our Codeless Automation. ## Browsing - **close** Simulates the user clicking the "close" button in the titlebar of a popup window or tab. - **closeAndWait** Simulates the user clicking the "close" button in the titlebar of a popup window or tab. - **goBack** Simulates the user clicking the "back" button on their browser. - **goBackAndWait** Simulates the user clicking the "back" button on their browser. - **open** (url) Opens an URL in the test frame. This accepts both relative and absolute URLs. The "open" command waits for the page to load before proceeding, ie. the "AndWait" suffix is implicit. Note: The URL must be on the same domain as the runner HTML due to security restrictions in the browser (Same Origin Policy). If you need to open an URL on another domain, use the Selenium Server to start a new browser session on that domain. - **openAndWait** (url) Opens an URL in the test frame. This accepts both relative and absolute URLs. The "open" command waits for the page to load before proceeding, ie. the "AndWait" suffix is implicit. Note: The URL must be on the same domain as the runner HTML due to security restrictions in the browser (Same Origin Policy). If you need to open an URL on another domain, use the Selenium Server to start a new browser session on that domain. - **openWindow** (url - windowID) Opens a popup window (if a window with that ID isn't already open). After opening the window, you'll need to select it using the selectWindow command. This command can also be a useful workaround for bug SEL-339. In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using an empty (blank) url, like this: openWindow("", "myFunnyWindow"). - **openWindowAndWait** (url - windowID) Opens a popup window (if a window with that ID isn't already open). After opening the window, you'll need to select it using the selectWindow command. This command can also be a useful workaround for bug SEL-339. In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using an empty (blank) url, like this: openWindow("", "myFunnyWindow"). - **refresh** Simulates the user clicking the "Refresh" button on their browser. - **refreshAndWait** Simulates the user clicking the "Refresh" button on their browser. - **selectFrame** (locator) Selects a frame within the current window. (You may invoke this command multiple times to select nested frames.) To select the parent frame, use "relative=parent" as a locator; to select the top frame, use "relative=top". You can also select a frame by its 0-based index number; select the first frame with "index=0", or the third frame with "index=2". You may also use a DOM expression to identify the frame you want directly, like this: dom=frames["main"].frames["subframe"] - **selectFrameAndWait** (locator) Selects a frame within the current window. (You may invoke this command multiple times to select nested frames.) To select the parent frame, use "relative=parent" as a locator; to select the top frame, use "relative=top". You can also select a frame by its 0-based index number; select the first frame with "index=0", or the third frame with "index=2". You may also use a DOM expression to identify the frame you want directly, like this: dom=frames["main"].frames["subframe"] - **selectWindow** (windowID) Selects a popup window using a window locator; once a popup window has been selected, all commands go to that window. To select the main window again, use null as the target. Window locators provide different ways of specifying the window object: by title, by internal JavaScript "name," or by JavaScript variable. title=My Special Window: Finds the window using the text that appears in the title bar. Be careful; two windows can share the same title. If that happens, this locator will just pick one. name=myWindow: Finds the window using its internal JavaScript "name" property. This is the second parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag) (which Selenium intercepts). var=variableName: Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using "var=foo". If no window locator prefix is provided, we'll try to guess what you mean like this: 1.) if windowID is null, (or the string "null") then it is assumed the user is referring to the original window instantiated by the browser). 2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed that this variable contains the return value from a call to the JavaScript window.open() method. 3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names". 4.) If that fails, we'll try looping over all of the known windows to try to find the appropriate "title". Since "title" is not necessarily unique, this may have unexpected behavior. If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages like the following for each window as it is opened: debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow" In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). (This is bug SEL-339.) In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using an empty (blank) url, like this: openWindow("", "myFunnyWindow"). - **selectWindowAndWait** (windowID) Selects a popup window using a window locator; once a popup window has been selected, all commands go to that window. To select the main window again, use null as the target. Window locators provide different ways of specifying the window object: by title, by internal JavaScript "name," or by JavaScript variable. title=My Special Window: Finds the window using the text that appears in the title bar. Be careful; two windows can share the same title. If that happens, this locator will just pick one. name=myWindow: Finds the window using its internal JavaScript "name" property. This is the second parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag) (which Selenium intercepts). var=variableName: Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using "var=foo". If no window locator prefix is provided, we'll try to guess what you mean like this: 1.) if windowID is null, (or the string "null") then it is assumed the user is referring to the original window instantiated by the browser). 2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed that this variable contains the return value from a call to the JavaScript window.open() method. 3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names". 4.) If that fails, we'll try looping over all of the known windows to try to find the appropriate "title". Since "title" is not necessarily unique, this may have unexpected behavior. If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages like the following for each window as it is opened: debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow" In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example). (This is bug SEL-339.) In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using an empty (blank) url, like this: openWindow("", "myFunnyWindow"). - **windowFocus** Gives focus to the currently selected window - **windowFocusAndWait** Gives focus to the currently selected window - **windowMaximize** Resize currently selected window to take up the entire screen - **windowMaximizeAndWait** Resize currently selected window to take up the entire screen ## Clicks - **click** (locator) Clicks on a link, button, checkbox or radio button. If the click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **clickAndWait** (locator) Clicks on a link, button, checkbox or radio button. If the click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **clickAt** (locator - coordString) Clicks on a link, button, checkbox or radio button. If the click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **clickAtAndWait** (locator - coordString) Clicks on a link, button, checkbox or radio button. If the click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **doubleClick** (locator) Double clicks on a link, button, checkbox or radio button. If the double click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **doubleClickAndWait** (locator) Double clicks on a link, button, checkbox or radio button. If the double click action causes a new page to load (like a link usually does), call waitForPageToLoad. - **doubleClickAt** (locator - coordString) Doubleclicks on a link, button, checkbox or radio button. If the action causes a new page to load (like a link usually does), call waitForPageToLoad. - **doubleClickAtAndWait** (locator - coordString) Doubleclicks on a link, button, checkbox or radio button. If the action causes a new page to load (like a link usually does), call waitForPageToLoad. - **dragAndDrop** (locator - movementsString) Drags an element a certain distance and then drops it - **dragAndDropAndWait** (locator - movementsString) Drags an element a certain distance and then drops it - **dragAndDropToObject** (locatorOfObjectToBeDragged - locatorOfDragDestinationObject) Drags an element and drops it on another element - **dragAndDropToObjectAndWait** (locatorOfObjectToBeDragged - locatorOfDragDestinationObject) Drags an element and drops it on another element ## Form Fields - **addSelection** (locator - optionLocator) Add a selection to the set of selected options in a multi-select element using an option locator. @see #doSelect for details of option locators - **addSelectionAndWait** (locator - optionLocator) Add a selection to the set of selected options in a multi-select element using an option locator. @see #doSelect for details of option locators - **check** (locator) Check a toggle-button (checkbox/radio) - **checkAndWait** (locator) Check a toggle-button (checkbox/radio) - **focus** (locator) Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field. - **focusAndWait** (locator) Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field. - **removeAllSelections** (locator) Unselects all of the selected options in a multi-select element. - **removeAllSelectionsAndWait** (locator) Unselects all of the selected options in a multi-select element. - **removeSelection** (locator - optionLocator) Remove a selection from the set of selected options in a multi-select element using an option locator. @see #doSelect for details of option locators - **removeSelectionAndWait** (locator - optionLocator) Remove a selection from the set of selected options in a multi-select element using an option locator. @see #doSelect for details of option locators - **select** (selectLocator - optionLocator) Select an option from a drop-down using an option locator. Option locators provide different ways of specifying options of an HTML Select element (e.g. for selecting a specific option, or for asserting that the selected option satisfies a specification). There are several forms of Select Option Locator. label=labelPattern: matches options based on their labels, i.e. the visible text. (This is the default.) label=regexp:^[Oo]ther value=valuePattern: matches options based on their values. value=other id=id: matches options based on their ids. id=option1 index=index: matches an option based on its index (offset from zero). index=2 If no option locator prefix is provided, the default behaviour is to match on label. - **selectAndWait** (selectLocator - optionLocator) Select an option from a drop-down using an option locator. Option locators provide different ways of specifying options of an HTML Select element (e.g. for selecting a specific option, or for asserting that the selected option satisfies a specification). There are several forms of Select Option Locator. label=labelPattern: matches options based on their labels, i.e. the visible text. (This is the default.) label=regexp:^[Oo]ther value=valuePattern: matches options based on their values. value=other id=id: matches options based on their ids. id=option1 index=index: matches an option based on its index (offset from zero). index=2 If no option locator prefix is provided, the default behaviour is to match on label. - **setCursorPosition** (locator - position) Moves the text cursor to the specified position in the given input element or textarea. This method will fail if the specified element isn't an input element or textarea. - **setCursorPositionAndWait** (locator - position) Moves the text cursor to the specified position in the given input element or textarea. This method will fail if the specified element isn't an input element or textarea. - **submit** (formLocator) Submit the specified form. This is particularly useful for forms without submit buttons, e.g. single-input "Search" forms. - **submitAndWait** (formLocator) Submit the specified form. This is particularly useful for forms without submit buttons, e.g. single-input "Search" forms. - **uncheck** (locator) Uncheck a toggle-button (checkbox/radio) - **uncheckAndWait** (locator) Uncheck a toggle-button (checkbox/radio) - **getSelectedLabels** (selectLocator) Gets all option labels (visible text) for selected options in the specified select or multi-select element. - **getSelectedLabel** (selectLocator) Gets option label (visible text) for selected option in the specified select element. - **getSelectedValues** (selectLocator) Gets all option values (value attributes) for selected options in the specified select or multi-select element. - **getSelectedValue** (selectLocator) Gets option value (value attribute) for selected option in the specified select element. - **getSelectedIndexes** (selectLocator) Gets all option indexes (option number, starting at 0) for selected options in the specified select or multi-select element. - **getSelectedIndex** (selectLocator) Gets option index (option number, starting at 0) for selected option in the specified select element. - **getSelectedIds** (selectLocator) Gets all option element IDs for selected options in the specified select or multi-select element. - **getSelectedId** (selectLocator) Gets option element ID for selected option in the specified select element. - **verifyAllButtons** (equalTo) - **verifyAllFields** (equalTo) - **verifyChecked** (locator) - **isChecked** (locator) Gets whether a toggle-button (checkbox/radio) is checked. Fails if the specified element doesn't exist or isn't a toggle-button. - **verifyCursorPosition** (locator - equalTo) - **verifyEditable** (locator) - **waitForElementEditable** (locator) - **verifyNotAllButtons** (equalTo) - **verifyNotAllFields** (equalTo) - **verifyNotChecked** (locator) - **verifyNotCursorPosition** (locator - equalTo) - **verifyNotEditable** (locator) - **verifyNotSelectedIds** (selectLocator - equalTo) - **verifyNotSelectedIndexes** (selectLocator - equalTo) - **verifyNotSelectedLabels** (selectLocator - equalTo) - **verifyNotSelectedValues** (selectLocator - equalTo) - **verifyNotSelectedOptions** (selectLocator - equalTo) - **verifyNotSomethingSelected** (selectLocator) - **verifyNotValue** (locator - equalTo) - **verifySelectedIds** (selectLocator - equalTo) - **verifySelectedIndexes** (selectLocator - equalTo) - **verifySelectedLabels** (selectLocator - equalTo) - **verifySelectedValues** (selectLocator - equalTo) - **verifySelectOptions** (selectLocator - equalTo) - **verifySomethingSelected** (selectLocator) - **isSomethingSelected** (selectLocator) Determines whether some option in a drop-down menu is selected. - **verifyValue** (locator - equalTo) - **assertAllButtons** (equalTo) - **assertAllFields** (equalTo) - **assertChecked** (locator) - **assertCursorPosition** (locator - equalTo) - **assertEditable** (locator) - **assertNotAllButtons** - **assertNotAllFields** - **assertNotChecked** (locator) - **assertNotCursorPosition** (locator - equalTo) - **assertNotEditable** (locator) - **assertNotSelectedIds** (selectLocator - equalTo) - **assertNotSelectedIndexes** (selectLocator - equalTo) - **assertNotSelectedLabels** (selectLocator - equalTo) - **assertNotSelectedValues** (selectLocator - equalTo) - **assertNotSelectOptions** (selectLocator - equalTo) - **assertNotSomethingSelected** (selectLocator) - **assertNotValue** (locator - equalTo) - **assertSelectedIds** (selectLocator - equalTo) - **assertSelectedIndexes** (selectLocator - equalTo) - **assertSelectedLabels** (selectLocator - equalTo) - **assertSelectedValues** (selectLocator - equalTo) - **assertSelectOptions** (selectLocator - equalTo) - **assertSomethingSelected** (selectLocator) - **assertValue** (locator - equalTo) - **waitForAllWindowIds** (equalTo) - **waitForAllWindowNames** (equalTo) - **waitForAllWindowTitles** (equalTo) - **waitForAttributeFromAllWindows** (attributeName - equalTo) - **waitForLocation** (equalTo) - **waitForNotAllWindowIds** (equalTo) - **waitForNotAllWindowNames** (equalTo) - **waitForNotAllWindowTitles** (equalTo) - **waitForNotAttributeFromAllWindows** (attributeName - equalTo) - **WaitForNotLocation** (equalTo) - **waitForNotTitle** (equalTo) - **waitForTitle** (equalTo) - **storeAllButtons** - **storeAllFields** - **storeChecked** (locator - variable) - **storeCursorPosition** (locator - variable) - **storeEditable** (locator - variable) - **storeSelectedIds** (selectLocator - variable) - **storeSelectedIndexes** (selectLocator - variable) - **storeSelectedLabels** (selectLocator - variable) - **storeSelectedValues** (selectLocator - variable) - **storeSelectOptions** (selectLocator - variable) - **storeSomethingSelected** (selectLocator - variable) - **storeValue** (locator - variable) ## Keyboard Events - **keyDown** (locator - keySequence) Simulates a user pressing a key (without releasing it yet). - **keyDownAndWait** (locator - keySequence) Simulates a user pressing a key (without releasing it yet). - **keyPress** (locator - keySequence) Simulates a user pressing and releasing a key. - **keyPressAndWait** (locator - keySequence) Simulates a user pressing and releasing a key. - **keyUp** (locator - keySequence) Simulates a user releasing a key. - **keyUpAndWait** (locator - keySequence) Simulates a user releasing a key. - **type** (locator - value) Sets the value of an input field, as though you typed it in. Can also be used to set the value of combo boxes, check boxes, etc. In these cases, value should be the value of the option selected, not the visible text. - **typeAndWait** (locator - value) Sets the value of an input field, as though you typed it in. Can also be used to set the value of combo boxes, check boxes, etc. In these cases, value should be the value of the option selected, not the visible text. - **typeKeys** (locator - value) Simulates keystroke events on the specified element, as though you typed the value key-by-key. This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string; this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events. Unlike the simple "type" command, which forces the specified value into the page directly, this command may or may not have any visible effect, even in cases where typing keys would normally have a visible effect. For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in the field. In some cases, you may need to use the simple "type" command to set the value of the field and then the "typeKeys" command to send the keystroke events corresponding to what you just typed. - **sendKeys** (locator - value) - **typeKeysAndWait** (locator - value) Simulates keystroke events on the specified element, as though you typed the value key-by-key. This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string; this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events. Unlike the simple "type" command, which forces the specified value into the page directly, this command may or may not have any visible effect, even in cases where typing keys would normally have a visible effect. For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in the field. In some cases, you may need to use the simple "type" command to set the value of the field and then the "typeKeys" command to send the keystroke events corresponding to what you just typed. ## Keyboard Modifiers - **altKeyDown** Press the alt key and hold it down until doAltUp() is called or a new page is loaded. - **altKeyDownAndWait** Press the alt key and hold it down until doAltUp() is called or a new page is loaded. - **altKeyUp** Release the alt key. - **altKeyUpAndWait** Release the alt key. - **controlKeyDown** Press the control key and hold it down until doControlUp() is called or a new page is loaded. - **controlKeyDownAndWait** Press the control key and hold it down until doControlUp() is called or a new page is loaded. - **controlKeyUp** Release the control key. - **controlKeyUpAndWait** Release the control key. - **metaKeyDown** Press the meta key and hold it down until doMetaUp() is called or a new page is loaded. - **metaKeyUp** Release the meta key. - **metaKeyUpAndWait** Release the meta key. - **shiftKeyDown** Press the shift key and hold it down until doShiftUp() is called or a new page is loaded. - **shiftKeyDownAndWait** Press the shift key and hold it down until doShiftUp() is called or a new page is loaded. - **shiftKeyUp** Release the shift key. - **shiftKeyUpAndWait** Release the shift key. ## Mouse Events - **mouseDown** (locator) Simulates a user pressing the left mouse button (without releasing it yet) on the specified element. - **mouseDownAndWait** (locator) Simulates a user pressing the left mouse button (without releasing it yet) on the specified element. - **mouseDownAt** (locator - coordString) Simulates a user pressing the left mouse button (without releasing it yet) at the specified location. - **mouseDownAtAndWait** (locator - coordString) Simulates a user pressing the left mouse button (without releasing it yet) at the specified location. - **mouseDownRight** (locator) Simulates a user pressing the right mouse button (without releasing it yet) on the specified element. - **mouseDownRightAndWait** (locator) Simulates a user pressing the right mouse button (without releasing it yet) on the specified element. - **mouseDownRightAt** (locator - coordString) Simulates a user pressing the right mouse button (without releasing it yet) at the specified location. - **mouseDownRightAtAndWait** (locator - coordString) Simulates a user pressing the right mouse button (without releasing it yet) at the specified location. - **mouseMove** (locator) Simulates a user pressing the mouse button (without releasing it yet) on the specified element. - **mouseMoveAndWait** (locator) Simulates a user pressing the mouse button (without releasing it yet) on the specified element. - **mouseMoveAt** (locator - coordString) Simulates a user pressing the mouse button (without releasing it yet) on the specified element. - **mouseMoveAtAndWait** (locator - coordString) Simulates a user pressing the mouse button (without releasing it yet) on the specified element. - **mouseOut** (locator) Simulates a user moving the mouse pointer away from the specified element. - **mouseOutAndWait** (locator) Simulates a user moving the mouse pointer away from the specified element. - **mouseOver** (locator) Simulates a user hovering a mouse over the specified element. - **mouseOverAndWait** (locator) Simulates a user hovering a mouse over the specified element. - **mouseUp** (locator) Simulates the event that occurs when the user releases the mouse button (i.e., stops holding the button down) on the specified element. - **mouseUpAndWait** (locator) Simulates the event that occurs when the user releases the mouse button (i.e., stops holding the button down) on the specified element. - **mouseUpAt** (locator - coordString) Simulates the event that occurs when the user releases the mouse button (i.e., stops holding the button down) at the specified location. - **mouseUpAtAndWait** (locator - coordString) Simulates the event that occurs when the user releases the mouse button (i.e., stops holding the button down) at the specified location. - **mouseUpRight** (locator) Simulates the event that occurs when the user releases the right mouse button (i.e., stops holding the button down) on the specified element. - **mouseUpRightAndWait** (locator) Simulates the event that occurs when the user releases the right mouse button (i.e., stops holding the button down) on the specified element. - **mouseUpRightAt** (locator - coordString) Simulates the event that occurs when the user releases the right mouse button (i.e., stops holding the button down) at the specified location. - **mouseUpRightAtAndWait** (locator - coordString) Simulates the event that occurs when the user releases the right mouse button (i.e., stops holding the button down) at the specified location. ## Popups and Menus - **answerOnNextPrompt** (answer) Instructs Selenium to return the specified answer string in response to the next JavaScript prompt [window.prompt()]. - **answerOnNextPromptAndWait** (answer) Instructs Selenium to return the specified answer string in response to the next JavaScript prompt [window.prompt()]. - **chooseCancelOnNextConfirmation** By default, Selenium's overridden window.confirm() function will return true, as if the user had manually clicked OK; after running this command, the next call to confirm() will return false, as if the user had clicked Cancel. Selenium will then resume using the default behavior for future confirmations, automatically returning true (OK) unless/until you explicitly call this command for each confirmation. Take note - every time a confirmation comes up, you must consume it with a corresponding getConfirmation, or else the next selenium operation will fail. - **chooseCancelOnNextConfirmationAndWait** By default, Selenium's overridden window.confirm() function will return true, as if the user had manually clicked OK; after running this command, the next call to confirm() will return false, as if the user had clicked Cancel. Selenium will then resume using the default behavior for future confirmations, automatically returning true (OK) unless/until you explicitly call this command for each confirmation. Take note - every time a confirmation comes up, you must consume it with a corresponding getConfirmation, or else the next selenium operation will fail. - **chooseOkOnNextConfirmation** Undo the effect of calling chooseCancelOnNextConfirmation. Note that Selenium's overridden window.confirm() function will normally automatically return true, as if the user had manually clicked OK, so you shouldn't need to use this command unless for some reason you need to change your mind prior to the next confirmation. After any confirmation, Selenium will resume using the default behavior for future confirmations, automatically returning true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each confirmation. Take note - every time a confirmation comes up, you must consume it with a corresponding getConfirmation, or else the next selenium operation will fail. - **chooseOkOnNextConfirmationAndWait** Undo the effect of calling chooseCancelOnNextConfirmation. Note that Selenium's overridden window.confirm() function will normally automatically return true, as if the user had manually clicked OK, so you shouldn't need to use this command unless for some reason you need to change your mind prior to the next confirmation. After any confirmation, Selenium will resume using the default behavior for future confirmations, automatically returning true (OK) unless/until you explicitly call chooseCancelOnNextConfirmation for each confirmation. Take note - every time a confirmation comes up, you must consume it with a corresponding getConfirmation, or else the next selenium operation will fail. - **contextMenu** (locator) Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). - **contextMenuAndWait** (locator) Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). - **contextMenuAt** (locator - coordString) Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). - **contextMenuAtAndWait** (locator - coordString) Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element). - **selectPopUp** (windowID) Simplifies the process of selecting a popup window (and does not offer functionality beyond what selectWindow() already provides). If windowID is either not specified, or specified as "null", the first non-top window is selected. The top window is the one that would be selected by selectWindow() without providing a windowID . This should not be used when more than one popup window is in play. Otherwise, the window will be looked up considering windowID as the following in order: 1) the "name" of the window, as specified to window.open(); 2) a javascript variable which is a reference to a window; and 3) the title of the window. This is the same ordered lookup performed by selectWindow . - **deselectPopUp** Selects the main window. Functionally equivalent to using selectWindow() and specifying no value for windowID. - **getAlert** Retrieves the message of a JavaScript alert generated during the previous action, or fail if there were no alerts. Getting an alert has the same effect as manually clicking OK. If an alert is generated but you do not consume it with getAlert, the next Selenium action will fail. Under Selenium, JavaScript alerts will NOT pop up a visible alert dialog. Selenium does NOT support JavaScript alerts that are generated in a page's onload() event handler. In this case a visible dialog WILL be generated and Selenium will hang until someone manually clicks OK. - **getConfirmation** Retrieves the message of a JavaScript confirmation dialog generated during the previous action. By default, the confirm function will return true, having the same effect as manually clicking OK. This can be changed by prior execution of the chooseCancelOnNextConfirmation command. If an confirmation is generated but you do not consume it with getConfirmation, the next Selenium action will fail. NOTE: under Selenium, JavaScript confirmations will NOT pop up a visible dialog. NOTE: Selenium does NOT support JavaScript confirmations that are generated in a page's onload() event handler. In this case a visible dialog WILL be generated and Selenium will hang until you manually click OK. - **getPrompt** Retrieves the message of a JavaScript question prompt dialog generated during the previous action. Successful handling of the prompt requires prior execution of the answerOnNextPrompt command. If a prompt is generated but you do not get/verify it, the next Selenium action will fail. NOTE: under Selenium, JavaScript prompts will NOT pop up a visible dialog. NOTE: Selenium does NOT support JavaScript prompts that are generated in a page's onload() event handler. In this case a visible dialog WILL be generated and Selenium will hang until someone manually clicks OK. - **getWhetherThisFrameMatchFrameExpression** (currentFrameString - target) Determine whether current/locator identify the frame containing this running code. This is useful in proxy injection mode, where this code runs in every browser frame and window, and sometimes the selenium server needs to identify the "current" frame. In this case, when the test calls selectFrame, this routine is called for each frame to figure out which one has been selected. The selected frame will return true, while all others will return false. - **getWhetherThisWindowMatchWindowExpression** (currentWindowString - target) Determine whether currentWindowString plus target identify the window containing this running code. This is useful in proxy injection mode, where this code runs in every browser frame and window, and sometimes the selenium server needs to identify the "current" window. In this case, when the test calls selectWindow, this routine is called for each window to figure out which one has been selected. The selected window will return true, while all others will return false. ## Browser Window - **verifyAllWindowIds** (equalTo) - **verifyAllWindowNames** (equalTo) - **verifyAllWindowTitles** (equalTo) - **verifyAttributeFromAllWindows** (attributeName - equalTo) - **verifyLocation** (equalTo) - **verifyNotAllWindowIds** (equalTo) - **verifyNotAllWindowNames** (equalTo) - **verifyNotAttributeFromAllWindows** (attributeName - equalTo) - **verifyNotLocation** (equalTo) - **verifyNotTitle** (equalTo) - **verifyTitle** (equalTo) - **assertAllWindowIds** (equalTo) - **assertAllWindowNames** (equalTo) - **assertAllWindowTitles** (equalTo) - **assertAttributeFromAllWindows** (attributeName - equalTo) - **assertLocation** (equalTo) - **assertNotAllWindowIds** (equalTo) - **assertNotAllWindowNames** (equalTo) - **assertNotAllWindowTitles** (equalTo) - **assertNotAttributeFromAllWindows** (attributeName) - **assertNotLocation** (equalTo) - **assertNotTitle** (equalTo) - **assertTitle** (equalTo) - **assert** Check that a variable is an expected value. The variable's value will be converted to a string for comparison. The test will stop if the assert fails. - **validateXml** Custom command by TestingBot. Validates if the document contents is valid XML. - **waitForAlert** (equalTo) - **waitForAlertNotPresent** - **waitForAlertPresent** - **waitForConfirmation** (equalTo) - **waitForConfirmationNotPresent** - **waitForConfirmationPresent** - **waitForNotAlert** (equalTo) - **waitForNotConfirmation** (equalTo) - **waitForNotPrompt** (equalTo) - **waitForPrompt** (equalTo) - **waitForPromptNotPresent** - **waitForPromptPresent** - **storeAllWindowIds** - **storeAllWindowNames** - **storeAllWindowTitles** - **storeAttributeFromAllWindows** (attributeName - variable) - **storeLocation** - **storeTitle** - **storeAllWindowHandles** - **storeNewWindowHandle** - **storeWindowHandle** - **setWindowSize** (size) Sets the current window size. ## Cookies - **verifyCookie** (equalTo) - **verifyCookieByName** (name - equalTo) - **verifyCookieNotPresent** (name) - **verifyCookiePresent** (name) - **verifyNotCookie** (equalTo) - **verifyNotCookieByName** (name - equalTo) - **assertCookie** (equalTo) - **assertCookieByName** (name - equalTo) - **assertCookieNotPresent** (name) - **assertCookiePresent** (name) - **assertNotCookie** (equalTo) - **assertNotCookieByName** (name - equalTo) - **createCookie** (nameValuePair - optionsString) Create a new cookie whose path and domain are same with those of current page under test, unless you specified a path for this cookie explicitly. - **deleteAllVisibleCookies** Calls deleteCookie with recurse=true on all cookies visible to the current page. As noted on the documentation for deleteCookie, recurse=true can be much slower than simply deleting the cookies using a known domain/path. - **deleteCookie** (name - optionsString) Delete a named cookie with specified path and domain. Be careful; to delete a cookie, you need to delete it using the exact same path and domain that were used to create the cookie. If the path is wrong, or the domain is wrong, the cookie simply won't be deleted. Also note that specifying a domain that isn't a subset of the current domain will usually fail. Since there's no way to discover at runtime the original path and domain of a given cookie, we've added an option called 'recurse' to try all sub-domains of the current domain with all paths that are a subset of the current path. Beware; this option can be slow. In big-O notation, it operates in O(n\*m) time, where n is the number of dots in the domain name and m is the number of slashes in the path. - **storeCookie** - **storeCookieByName** (name - variable) - **storeCookiePresent** (name - variable) ## Page Content - **verifyAllLinks** (equalTo) - **verifyAttribute** (attributeLocator - equalTo) - **verifyBodyText** (equalTo) - **verifyElementNotPresent** (locator) - **verifyElementPresent** (locator) - **verifyHtmlSource** (equalTo) - **verifyNotAllLinks** (equalTo) - **verifyNotAttribute** (attributeLocator) - **verifyNotBodyText** (equalTo) - **verifyNotHtmlSource** (equalTo) - **verifyNotOrdered** (locator1 - locator2) - **verifyNotTable** (tableCellAddress - equalTo) - **verifyNotText** (locator - equalTo) - **verifyNotVisible** (locator) - **verifyOrdered** (locator1 - locator2) - **verifyTable** (tableCellAddress - equalTo) - **verifyText** (locator - equalTo) - **verifyTextNotPresent** (pattern) - **verifyTextPresent** (pattern) - **verifyVisible** (locator) - **assertAllLinks** (equalTo) - **assertAttribute** (attributeLocator - equalTo) - **assertBodyText** (equalTo) - **assertElementNotPresent** (locator) - **assertElementPresent** (locator) - **assertHtmlSource** (equalTo) - **assertNotAllLinks** (equalTo) - **assertNotAttribute** (attributeLocator - equalTo) - **assertNotBodyText** (equalTo) - **assertNotHtmlSource** (equalTo) - **assertNotOrdered** (locator1 - locator2) - **assertNotTable** (tableCellAddress - equalTo) - **assertNotText** (locator - equalTo) - **assertNotVisible** (locator) - **assertOrdered** (locator1 - locator2) - **assertTable** (tableCellAddress - equalTo) - **assertText** (locator - equalTo) - **assertTextNotPresent** (pattern) - **assertTextPresent** (pattern) - **assertVisible** (locator) - **waitForAllLinks** (equalTo) - **waitForAttribute** (attributeLocator - equalTo) - **waitForBodyText** (equalTo) - **waitForElementPresent** (locator) - **waitForHtmlSource** (equalTo) - **waitForNotAllLinks** (equalTo) - **waitForNotAttribute** (attributeLocator - equalTo) - **waitForNotBodyText** (equalTo) - **waitForElementNotPresent** (locator) - **waitForElementNotVisible** (locator) - **waitForElementVisible** (locator) - **waitForNotHtmlSource** (equalTo) - **waitForNotOrdered** (locator1 - locator2) - **waitForNotTable** (tableCellAddress - equalTo) - **waitForNotText** (locator - equalTo) - **waitForNotVisible** (locator) - **waitForOrdered** (locator1 - locator2) - **waitForTable** (tableCellAddress - equalTo) - **waitForText** (locator - equalTo) - **waitForTextNotPresent** (pattern) - **waitForTextPresent** (pattern) - **waitForVisible** (locator) - **storeAllLinks** - **storeAttribute** (attributeLocator - variable) - **storeBodyText** - **storeElementPresent** (locator - variable) - **storeHtmlSource** - **storeTable** (tableCellAddress - variable) - **storeText** (locator - variable) - **storeTextPresent** (pattern - variable) - **storeVisible** (locator - variable) ## Page Positioning - **verifyElementHeight** (locator - equalTo) - **verifyElementIndex** (locator - equalTo) - **verifyElementPositionLeft** (locator - equalTo) - **verifyElementPositionTop** (locator - equalTo) - **verifyElementWidth** (locator - equalTo) - **verifyNotElementHeight** (locator - equalTo) - **verifyNotElementIndex** (locator - equalTo) - **verifyNotElementPositionLeft** (locator - equalTo) - **verifyNotElementPositionTop** (locator - equalTo) - **verifyNotElementWidth** (locator - equalTo) - **assertElementHeight** (locator - equalTo) - **assertElementIndex** (locator - equalTo) - **assertElementPositionLeft** (locator - equalTo) - **assertElementPositionTop** (locator - equalTo) - **assertElementWidth** (locator - equalTo) - **assertNotElementHeight** (locator - equalTo) - **assertNotElementIndex** (locator - equalTo) - **assertNotElementPositionLeft** (locator - equalTo) - **assertNotElementPositionTop** (locator - equalTo) - **assertNotElementWidth** - **storeElementHeight** (locator - variable) - **storeElementIndex** (locator - variable) - **storeElementPositionLeft** (locator - variable) - **storeElementPositionTop** (locator - variable) - **storeElementWidth** (locator - variable) ## Popups - **verifyAlert** (equalTo) - **verifyAlertNotPresent** - **verifyAlertPresent** - **isAlertPresent** Has an alert occurred? This function never throws an exception - **verifyConfirmation** (equalTo) - **verifyConfirmationNotPresent** - **verifyConfirmationPresent** - **isConfirmationPresent** Has confirm() been called? This function never throws an exception - **verifyNotAlert** (equalTo) - **verifyNotConfirmation** (equalTo) - **verifyNotPrompt** (equalTo) - **verifyPrompt** (equalTo) - **verifyPromptNotPresent** - **verifyPromptPresent** - **isPromptPresent** Has a prompt occurred? This function never throws an exception - **assertAlert** (equalTo) - **assertAlertNotPresent** - **assertAlertPresent** - **assertConfirmation** (equalTo) - **assertConfirmationNotPresent** - **assertConfirmationPresent** - **assertNotAlert** (equalTo) - **assertNotConfirmation** (equalTo) - **assertNotPrompt** (equalTo) - **assertPrompt** (equalTo) - **assertPromptNotPresent** - **assertPromptPresent** - **waitForElementHeight** (locator - equalTo) - **waitForElementIndex** (locator - equalTo) - **waitForElementPositionLeft** (locator - equalTo) - **waitForElementPositionTop** (locator - equalTo) - **waitForElementWidth** (locator - equalTo) - **waitForNotElementHeight** (locator - equalTo) - **waitForNotElementIndex** (locator - equalTo) - **waitForNotElementPositionLeft** (locator - equalTo) - **waitForNotElementPositionTop** (locator - equalTo) - **waitForNotElementWidth** (locator - equalTo) - **waitForPopUp** (windowID - timeout) Waits for a popup window to appear and load up. - **storeAlert** - **storeAlertPresent** - **storeConfirmation** - **storeConfirmationPresent** - **storePrompt** - **storePromptPresent** ## Selenium - **verifyEval** (script - equalTo) - **verifyExpression** (expression - equalTo) - **verifyMouseSpeed** - **verifyNotEval** (script - equalTo) - **verifyNotExpression** (expression - equalTo) - **verifyNotMouseSpeed** - **verifyNotSpeed** - **verifyNotXpathCount** (xpath - equalTo) - **verifySpeed** - **verifyXpathCount** (xpath - equalTo) - **assertEval** (script - equalTo) - **assertExpression** (expression - equalTo) - **assertMouseSpeed** (equalTo) - **assertNotEval** (script - equalTo) - **assertNotExpression** (expression - equalTo) - **assertNotMouseSpeed** (equalTo) - **assertNotSpeed** (equalTo) - **assertNotXpathCount** (xpath - equalTo) - **assertSpeed** (equalTo) - **assertXpathCount** (xpath - equalTo) - **waitForAllButtons** (equalTo) - **waitForAllFields** (equalTo) - **waitForChecked** (locator) - **waitForCursorPosition** (locator - equalTo) - **waitForCondition** (script - timeout) Runs the specified JavaScript snippet repeatedly until it evaluates to "true". The snippet may have multiple lines, but only the result of the last line will be considered. Note that, by default, the snippet will be run in the runner's test window, not in the window of your application. To get the window of your application, you can use the JavaScript snippet selenium.browserbot.getCurrentWindow(), and then run your JavaScript in there - **waitForEditable** (locator) - **waitForEval** (script - equalTo) - **waitForExpression** (expression - equalTo) - **waitForMouseSpeed** (equalTo) - **waitForNotAllButtons** (equalTo) - **waitForNotAllFields** (equalTo) - **waitForNotChecked** (locator) - **waitForNotCursorPosition** (locator - equalTo) - **waitForNotEditable** (locator) - **waitForNotEval** (script - equalTo) - **waitForNotExpression** (expression - equalTo) - **waitForNotMouseSpeed** (equalTo) - **waitForNotSelectedIds** (selectLocator - equalTo) - **waitForNotSelectedIndexes** (selectLocator - equalTo) - **waitForNotSelectedLabels** (selectLocator - equalTo) - **waitForNotSelectedValues** (selectLocator - equalTo) - **waitForNotSelectOptions** (selectLocator - equalTo) - **waitForNotSomethingSelected** (selectLocator) - **waitForNotSpeed** (equalTo) - **waitForNotValue** (locator - equalTo) - **waitForNotXpathCount** (xpath - equalTo) - **waitForSelectedIds** (selectLocator - equalTo) - **waitForSelectedIndexes** (selectLocator - equalTo) - **waitForSelectedLabels** (selectLocator - equalTo) - **waitForSelectedValues** (selectLocator - equalTo) - **waitForSelectOptions** (selectLocator - equalTo) - **waitForSomethingSelected** (selectLocator) - **waitForSpeed** (equalTo) - **waitForValue** (locator - equalTo) - **waitForXpathCount** (xpath - equalTo) - **storeEval** (script - variable) - **storeExpression** (expression - variable) - **store** (expression - variable) This command is a synonym for storeExpression. - **storeMouseSpeed** - **storeSpeed** - **storeXpathCount** (xpath - variable) ## Screenshots - **captureEntirePageScreenshot** (filename - kwargs) Saves the entire contents of the current window canvas to a PNG file. Contrast this with the captureScreenshot command, which captures the contents of the OS viewport (i.e. whatever is currently being displayed on the monitor), and is implemented in the RC only. Currently this only works in Firefox when running in chrome mode, and in IE non-HTA using the EXPERIMENTAL "Snapsie" utility. The Firefox implementation is mostly borrowed from the Screengrab! Firefox extension. Please see http://www.screengrab.org and http://snapsie.sourceforge.net/ for details. ## Selenium Settings - **waitForCookie** (equalTo) - **waitForCookieByName** (name - equalTo) - **waitForCookieNotPresent** (name) - **waitForCookiePresent** (name) - **waitForNotCookie** (equalTo) - **waitForNotCookieByName** (name - equalTo) - **addLocationStrategy** (strategyName - functionDefinition) Defines a new function for Selenium to locate elements on the page. For example, if you define the strategy "foo", and someone runs click("foo=blah"), we'll run your function, passing you the string "blah", and click on the element that your function returns, or throw an "Element not found" error if your function returns null. We'll pass three arguments to your function: locator: the string the user passed in inWindow: the currently selected window inDocument: the currently selected document The function must return null if the element can't be found. - **allowNativeXpath** (allow) Specifies whether Selenium should use the native in-browser implementation of XPath (if any native version is available); if you pass "false" to this function, we will always use our pure-JavaScript xpath library. Using the pure-JS xpath library can improve the consistency of xpath element locators between different browser vendors, but the pure-JS version is much slower than the native implementations. - **ignoreAttributesWithoutValue** (ignore) Specifies whether Selenium will ignore xpath attributes that have no value, i.e. are the empty string, when using the non-native xpath evaluation engine. You'd want to do this for performance reasons in IE. However, this could break certain xpaths, for example an xpath that looks for an attribute whose value is NOT the empty string. The hope is that such xpaths are relatively rare, but the user should have the option of using them. Note that this only influences xpath evaluation when using the ajaxslt engine (i.e. not "javascript-xpath"). - **setBrowserLogLevel** (logLevel) Sets the threshold for browser-side logging messages; log messages beneath this threshold will be discarded. Valid logLevel strings are: "debug", "info", "warn", "error" or "off". To see the browser logs, you need to either show the log window in GUI mode, or enable browser-side logging in Selenium RC. - **setMouseSpeed** (pixels) Configure the number of pixels between "mousemove" events during dragAndDrop commands (default=10). Setting this value to 0 means that we'll send a "mousemove" event to every single pixel in between the start location and the end location; that can be very slow, and may cause some browsers to force the JavaScript to timeout. If the mouse speed is greater than the distance between the two dragged objects, we'll just send one "mousemove" at the start location and then one final one at the end location. - **setSpeed** (value) Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation). By default, there is no such delay, i.e., the delay is 0 milliseconds. - **getSpeed** Get execution speed (i.e., get the millisecond length of the delay following each selenium operation). By default, there is no such delay, i.e., the delay is 0 milliseconds. See also setSpeed. - **setTimeout** (timeout) Specifies the amount of time that Selenium will wait for actions to complete. Actions that require waiting include "open" and the "waitFor\*" actions. The default timeout is 30 seconds. - **useXpathLibrary** (libraryName) Allows choice of one of the available libraries. ## Special - **addScript** (scriptContent - scriptTagId) Loads script content into a new script tag in the Selenium document. This differs from the runScript command in that runScript adds the script tag to the document of the AUT, not the Selenium document. The following entities in the script content are replaced by the characters they represent: \< \> & The corresponding remove command is removeScript. - **assignId** (locator - identifier) Temporarily sets the "id" attribute of the specified element, so you can locate it in the future using its ID rather than a slow/complicated XPath. This ID will disappear once the page is reloaded. - **echo** (message) Prints the specified message into the third table cell in your Selenese tables. Useful for debugging. - **fireEvent** (locator - eventName) Explicitly simulate an event, to trigger the corresponding "onevent" handler. - **highlight** (locator) Briefly changes the backgroundColor of the specified element yellow. Useful for debugging. - **rollup** (rollupName - kwargs) Executes a command rollup, which is a series of commands with a unique name, and optionally arguments that control the generation of the set of commands. If any one of the rolled-up commands fails, the rollup is considered to have failed. Rollups may also contain nested rollups. - **runScript** (script) Creates a new "script" tag in the body of the current test window, and adds the specified text into the body of the command. Scripts run in this way can often be debugged more easily than scripts executed using Selenium's "getEval" command. Beware that JS exceptions thrown in these script tags aren't managed by Selenium, so you should probably wrap your script in try/catch blocks if there is any chance that the script will throw an exception. - **getEval** (command) Gets the result of evaluating the specified JavaScript snippet. The snippet may have multiple lines, but only the result of the last line will be returned. Note that, by default, the snippet will run in the context of the "selenium" object itself, so this will refer to the Selenium object. Use window to refer to the window of your application, e.g. window.document.getElementById('foo') If you need to use a locator to refer to a single element in your application page, you can use this.browserbot.findElement("id=foo") where "id=foo" is your locator. - **getLocation** Gets the absolute URL of the current page. - **getTitle** Gets the title of the current page. - **getBodyText** Gets the entire text of the page. - **getValue** (locator) Gets the (whitespace-trimmed) value of an input field (or anything else with a value parameter). For checkbox/radio elements, the value will be "on" or "off" depending on whether the element is checked or not. - **getText** (locator) Gets the text of an element. This works for any element that contains text. This command uses either the textContent (Mozilla-like browsers) or the innerText (IE-like browsers) of the element, which is the rendered text shown to the user. - **getTable** (tableCellAddress) Gets the text from a cell of a table. The cellAddress syntax tableLocator.row.column, where row and column start at 0. - **pause** (time) Wait for the specified amount of time (in milliseconds) - **comment** (text) Custom command by TestingBot. Add a comment between your test steps. This will show up in the test results. - **getHtmlSource** Returns the entire HTML source between the opening and closing "html" tags. - **stopTest** (condition) Custom command by TestingBot. Will stop the test if the supplied condition is met. Other steps, which resulted in an error, after a successful stopTest, will no longer indicate a test as failed. ## Common - **waitForPageToLoad** (timeout) Waits for a new page to load. You can use this command instead of the "AndWait" suffixes, "clickAndWait", "selectAndWait", "typeAndWait" etc. (which are only available in the JS API). Selenium constantly keeps track of new pages loading, and sets a "newPageLoaded" flag when it first notices a page load. Running any other Selenium command after turns the flag to false. Hence, if you want to wait for a page to load, you must wait immediately after a Selenium command that caused a page-load. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/faq # Selenium IDE FAQ TestingBot supports importing and running Selenium IDE tests on all our browsers and devices. Please find some questions and answers below. ## FAQ - **How do I use `selenium-side-runner` with TestingBot?** You can easily run your tests with `selenium-side-runner`, try this command for example selenium-side-runner --server http://key:secret@hub.testingbot.com/wd/hub -c "browserName='internet explorer' version='11.0' platform='Windows 8.1'" my-test-file.side This will run the test on our Grid on IE11 - the test results will appear in the TestingBot dashboard. - **Do you support the old Selenium IDE format? What about the .SIDE format?** We support both versions in our TestLab. You can upload the old format (in `HTML` format) or newly generated tests (in `SIDE` format). - **Do you support control flow?** We do not yet support control flow, like `if`, `else`, `while`, ... If you need this feature, please [contact us](https://testingbot.com/contact/new). - **Do you support mobile testing with Codeless Automation?** We support running your tests on our iOS and Android simulators/emulators. Please consider using `css selectors` as much as possible, as Appium (which we use to control iOS/Android) does not support XPath selectors. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/codeless-automation/variables # Storing Selenium IDE Variables With Selenium IDE it is possible to `store` variables. These variables can then be used in later commands during the same test flow. ## How to store a variable To store a variable during a test, please use the `store` command: store - javascript(return "test" + Math.floor(Math.random()*11111) + "@test.com") - emailAddress This example will store a variable called `emailAddress` and its value will be a random `"test....@test.com"` string. Storing a variable happens in the context of the page. You can use any kind of javascript and reference DOM elements or other functions available on the page. The return value is stored. ## How to use a variable Once you have stored a variable, you can use it in subsequent steps like this: `${emailAddress}` ## Examples Below are some examples on how to [store and use variables](https://www.selenium.dev/selenium-ide/docs/en/api/commands#store). storeText("css=.container:nth-child(1) > span:nth-child(3)","myVar") This will store the text from element with CSS selector `.container:nth-child(1) > span:nth-child(3)` in a variable called `myVar`. type('id=inputField','${myVar}') This will type the text stored in the `myVar` variable to an element with `ID=inputField` Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai # AI Testing TestingBot provides AI solutions for QA and developers to automate their tests and other tasks. Here are some of the AI solutions we are providing: - [TestingBot AI Chat](https://testingbot.com/support/ai/chat) Chat with an AI operator and instruct a remote browser. Generate automated tests from your instructions. - [Codeless Tests](https://testingbot.com/support/ai/codeless) Instruct our AI agent what to test. The AI agent will run tests against your website on regular intervals and alert if a test fails. - [TestingBot MCP Server](https://testingbot.com/support/ai/mcp) Connect TestingBot with AI models, using the TestingBot MCP Server. - [Other AI integrations such as Functions and Browser-Use](https://testingbot.com/support/ai/integrations) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations # TestingBot's Remote Browser Cloud TestingBot offers a battle-tested remote browser cloud, available to run both automated tests and AI tasks. When it comes to running AI-driven browser automation tasks, selecting the right remote browser grid is crucial. **TestingBot** offers a scalable, feature-rich alternative to platforms like Browserbase, Steel.dev, Browserless and Lightpanda. At TestingBot we've been operating a browser grid since 2012, providing unmatched reliability, global coverage and enterprise-grade security. ### Comparison Table | Feature | TestingBot | Browserbase | Steel.dev | Browserless | Lightpanda | | --- | --- | --- | --- | --- | --- | | Real Browsers & Devices | ✅ Yes | ❌ No | ❌ No | ❌ No | ❌ No | | Headless Browsers | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | | Global Testing Locations | ✅ Yes | ✅ Yes | ❌ No | ❌ No | ❌ No | | Parallel Sessions | ✅ Unlimited | ❌ Limited | ✅ Yes | ❌ Limited | ❌ Limited | | Security & Compliance | ✅ Enterprise-Grade | ❌ Basic | ❌ Basic | ❌ Basic | ❌ Basic | ## AI Integrations TestingBot is capable of connecting remote browsers to various AI frameworks and libraries, including the following popular options: - [AgentKit](https://testingbot.com/support/ai/integrations/agentkit) - Create AI agents that can run browser automation tasks using TestingBot's remote browser grid and AgentKit. - [Browser-Use](https://testingbot.com/support/ai/integrations/browser-use) - A Python library for browser automation using AI agents. - [Braintrust](https://testingbot.com/support/ai/integrations/braintrust) - Create tools to leverage AI for testing and automation. - [Stagehand](https://testingbot.com/support/ai/integrations/stagehand) - An AI Browser Automation Framework that allows you to create and manage browser automation tasks using AI. - [Magnitude](https://testingbot.com/support/ai/integrations/magnitude) - An AI framework using Vision to perform automated browser automation with LLMs. - [Notte](https://testingbot.com/support/ai/integrations/notte) - A reliable and fast AI browser agent. ## Scraping data with real browsers Looking to obtain data from the world wide web with real browsers? You can connect your [Puppeteer](https://testingbot.com/support/web-automate/puppeteer) and [Playwright](https://testingbot.com/support/web-automate/playwright) scripts to the large TestingBot browser grid, or use functions to perform tasks without writing any code: - [Take screenshots](https://testingbot.com/support/functions/screenshot) - [Generate PDFs](https://testingbot.com/support/functions/pdf) - [Scrape Webpages](https://testingbot.com/support/functions/scrape) - [Serverless Functions](https://testingbot.com/support/functions/serverless) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/agentkit # Using AgentKit with TestingBot Create AI agents that can run browser automation tasks using TestingBot's remote browser grid and AgentKit (by inngest). ## Dependencies To install all dependencies, please follow these steps: [npm](https://testingbot.com#)[pnpm](https://testingbot.com#)[yarn](https://testingbot.com#) npm install @inngest/agent-kit playwright-core pnpm add @inngest/agent-kit playwright-core yarn add @inngest/agent-kit playwright-core ## Create a TestingBot service In the example below, we'll show an example tool that will use Algolia to search Hacker News (HN) posts. The TestingBot remote browser grid will be used to perform the actions and return the results. The example below uses the `chromium.connect` method to connect to a remote browser in the TestingBot cloud. There are a lot of [Playwright Options](https://testingbot.com/support/web-automate/playwright/options) you can use to customize the browser session. Make sure to replace `key` and `secret` with your TestingBot API key and secret. import "dotenv/config"; import { anthropic, createAgent, createNetwork, createTool, } from "@inngest/agent-kit"; import { createServer } from "@inngest/agent-kit/server"; import { z } from "zod"; import { chromium } from "playwright-core"; const searchHN = createTool({ name: "search_hn", description: "Search HN posts and comments", parameters: z.object({ query: z.string().describe("The search query for HN"), }), handler: async ({ query }, { step }) => { return await step?.run("search-on-hn", async () => { const browser = await chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?key=${testingBotKey}&secret=${testingBotSecret}&browserName=chrome&browserVersion=latest`, }); try { const page = await browser.newPage(); // Construct the search URL const searchUrl = `https://hn.algolia.com/?dateRange=all&page=0&prefix=false&query=${query}&sort=byPopularity&type=story`; await page.goto(searchUrl); // Wait for results to load await page.waitForSelector(".SearchResults", { timeout: 10000 }); // Extract search results const results = await page.evaluate(() => { const posts = document.querySelectorAll(".SearchResults .Story "); return Array.from(posts).map((post) => ({ title: post.querySelector(".Story_title span")?.textContent?.trim(), })); }); return results.slice(0, 5); // Return top 5 results } finally { await browser.close(); } }); }, }); // Create the search agent const searchAgent = createAgent({ name: "hn_searcher", description: "An agent that searches HN for relevant information", system: "You are a helpful assistant that searches HN through algolia for relevant information.", tools: [searchHN], }); // Create the network const hnSearchNetwork = createNetwork({ name: "hn-search-network", description: "A network that searches HN using TestingBot", agents: [searchAgent], maxIter: 2, defaultModel: anthropic({ model: "claude-3-5-sonnet-latest", defaultParameters: { max_tokens: 4096, }, }), }); // Create and start the server const server = createServer({ networks: [hnSearchNetwork], }); server.listen(3010, () => console.log("HN Search Agent server is running on port 3010") ); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/braintrust # Using BrainTrust with TestingBot ## Braintrust Organization To get started, make sure you create [a new Braintrust organization](https://www.braintrust.dev/docs/guides/projects). Next, install the necessary dependencies: ## Install dependencies To use Braintrust with TestingBot, you need to install the following dependencies: npm install zod braintrust playwright-core ## Variables To use TestingBot with Braintrust, you need to set the following environment variables: `TESTINGBOT_KEY` and `TESTINGBOT_SECRET`. You will also need to set up the AI API Key that you are using. Braintrust supports various AI providers, such as OpenAI, Anthropic and others. ## Tools Braintrust allows you to create [tools](https://www.braintrust.dev/docs/guides/functions/tools) that can be used by agents. In this example, we will create a tool that takes a URL parameter and will use Readability to convert the HTML. import * as braintrust from "braintrust"; import { z } from "zod"; import { chromium } from "playwright-core"; async function loadPage({ url }: { url: string }) { const { id } = await createSession(); const browser = await chromium.connectOverCDP( wsEndpoint: `wss://cloud.testingbot.com/playwright?key=${testingBotKey}&secret=${testingBotSecret}&browserName=chrome&browserVersion=latest`, ); const defaultContext = browser.contexts()[0]; const page = defaultContext.pages()[0]; await page.goto(url); const readable: { title?: string; textContent?: string } = await page.evaluate(` import('https://cdn.skypack.dev/@mozilla/readability').then(readability => { return new readability.Readability(document).parse() })`); const text = `${readable.title}\n${readable.textContent}`; return { page: text }; } const project = braintrust.projects.create({ name: "TestingBot API Tool" }); project.tools.create({ handler: loadPage, parameters: z.object({ url: z.string(), }), returns: z.object({ page: z.string(), }), name: "Load page", slug: "load-page", description: "Load a page from the internet", ifExists: "replace", }); ## Deploy tool You can now deploy the tool to Braintrust. You can do this by running the following command: npx braintrust push testingbot.ts Once the tool is deployed, you will see the tool listed in the Library's Tools section. Now you can specify a URL and use the "Load page" tool to use the TestingBot tool. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/browser-use # Browser Use Cloud API Browser-Use is a Python library that allows you to create browser automation scripts using AI. You can use multiple models such as GPT-4o, DeepSeek, Gemini-2.0, Claude and more. Local models such as Qwen 2.5 are also supported. The library essentially uses a Playwright browser instance to execute tasks on a (remote) browser. You can perform tasks such as: - Navigate to Google and search for TestingBot - Go to Reddit and open an article - Open a new tab and go to CNN By using the TestingBot remote browser grid, you can run multiple AI agents in parallel without worrying about setting up and managing the browsers yourself. Additionally, TestingBot records each session with a video, logs and generated metadata are saved as well. You can run browsers from [various geographical locations](https://testingbot.com/support/web-automate/playwright/options#geo) and use different browser versions, on multiple operating systems. To install browser use, please follow these steps: - Install the Browser-Use library: `pip install browser-use` - Install the Playwright library: `pip install playwright` ## Connecting to a remote browser Please see the example below on how to connect your Browser-Use agent to a remote browser in the TestingBot cloud. The `wss` URL points to the TestingBot cloud, where you can specify the browser and platform you want to use. You can also specify the name of the session. Make sure to replace `key` and `secret` with your TestingBot API key and secret. import json import httpx import os import asyncio import logging from browser_use.browser import BrowserSession from browser_use.agent.service import Agent from browser_use.llm import ChatOpenAI capabilities = { "tb:options": { "name": "Browser Use Example", "key": os.environ["TESTINGBOT_KEY"], "secret": os.environ["TESTINGBOT_SECRET"], }, "browserName": "chrome", "browserVersion": "latest", "platform": "WIN10" } async def create_testingbot_session(): try: async with httpx.AsyncClient(timeout=600.0) as client: response = await client.post( "https://cloud.testingbot.com/session", json={ "capabilities": capabilities }, ) response.raise_for_status() session_data = response.json() logging.info( "TestingBot session created successfully: %s", json.dumps(session_data, indent=2) ) return session_data except Exception as e: logging.error("Failed to create TestingBot session: %s", e) async def main(): session_data = await create_testingbot_session() cdp_url = session_data["cdp_url"] browser_session = BrowserSession(cdp_url=cdp_url) agent = Agent( task="Go to the TestingBot homepage and click the pricing menu item", llm=ChatOpenAI(model="gpt-4o"), browser_session=browser_session, ) try: await agent.run() finally: await browser_session.close() if __name__ == " __main__": asyncio.run(main()) When you run this example, the Browser-Use agent will connect to a remote browser in the TestingBot cloud, and execute the task specified in the `task` variable. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/stagehand # TestingBot & Stagehand Stagehand is an AI Browser Automation Framework that allows you to create and manage browser automation tasks using AI. It is available in both NodeJS and Python. By connecting Stagehand to TestingBot's remote browser grid, you can run multiple AI-driven browser automation tasks in parallel, without the need to manage the browsers yourself. Each session is video recorded and available for replay in the TestingBot dashboard. You can run browsers from [various geographical locations](https://testingbot.com/support/web-automate/playwright/options#geo) and use different browser versions, on multiple operating systems. ## Connecting to a remote browser To get started, please install these packages: - Install the Stagehand library: `@browserbasehq/stagehand` - Install the TestingBot library: `npm install testingbot-api` We can now run a simple example. This will connect Stagehand with a remote TestingBot browser session. Use the AI prompt to test a specific scenario, by describing what you want to test in your own natural language. const { Stagehand } = require("@browserbasehq/stagehand"); const TestingBot = require("testingbot-api"); (async () => { const tb = new TestingBot({ api_key: process.env.TESTINGBOT_KEY, api_secret: process.env.TESTINGBOT_SECRET }); const options = { capabilities: { browserName: 'chrome', browserVersion: 'latest', platform: 'WIN11' } }; const session = await tb.createSession(options); const stagehand = new Stagehand({ env: "LOCAL", localBrowserLaunchOptions: { cdpUrl: session['cdp_url'] } }); await stagehand.init(); const page = stagehand.page; await page.goto("https://testingbot.com/pricing"); const extractResult = await page.extract("Extract the pricing plans from this page"); console.log(`Extract result:\n`, extractResult); })(); Make sure to replace `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` with your actual TestingBot API key and secret. In the example above, we create a new TestingBot session with the desired capabilities. We then pass the `cdpUrl` to Stagehand, which allows it to connect to the remote browser session on TestingBot. You can now use Stagehand's AI capabilities to interact with the page, extract information, or perform other actions as needed. For more information on using Stagehand, please refer to the [Stagehand documentation](https://docs.stagehand.dev/first-steps/quickstart). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/magnitude # Magnitude AI [Magnitude](https://github.com/magnitudedev/magnitude) is an AI browser automation framework that allows you to run browser automation scripts using AI models. It uses Vision AI to understand the webpage and interact with it, making it possible to automate tasks that require visual understanding. You can use the framework to automate tasks on webpages, test functionality, extract data and verify any specific behavior on the webpage, just like a normal user would do. ## Running Magnitude AI tests on TestingBot To run Magnitude AI tests on TestingBot, you can use the following steps and example code to get started: - `npx create-magnitude-app` - Next, modify the `src/index.tsx` file that was generated, add a `browser` option to the `startBrowserAgent` function. import { startBrowserAgent } from "magnitude-core"; import z from 'zod'; import dotenv from 'dotenv'; dotenv.config(); const capabilities = { 'tb:options': { key: process.env.TESTINGBOT_KEY, secret: process.env.TESTINGBOT_SECRET, }, browserName: 'chrome', browserVersion: 'latest' } async function main() { const agent = await startBrowserAgent({ // Starting URL for agent url: 'https://docs.magnitude.run/getting-started/quickstart', // Show thoughts and actions narrate: true, browser: { cdp: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` } }); // Intelligently extract data based on the DOM content matching a provided zod schema const gettingStarted = await agent.extract('Extract how to get started with Magnitude', z.object({ // Agent can extract existing data or new insights difficulty: z.enum(['easy', 'medium', 'hard']), steps: z.array(z.string()), })); // Navigate to a new URL await agent.nav('https://magnitasks.com'); // Magnitude can handle high-level tasks await agent.act('Create a task', { // Optionally pass data that the agent will use where appropriate data: { title: 'Get started with Magnitude', description: gettingStarted.steps.map(step => `• ${step}`).join('\n') } }); // It can also handle low-level actions await agent.act('Drag "Get started with Magnitude" to the top of the in progress column'); // Stop agent and browser await agent.stop(); } main(); When you run this example, the Magnitude AI agent will use a remote TestingBot browser to interact with. Results will appear on your machine. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/integrations/notte # Notte Browser Agent [Notte](https://github.com/nottelabs/notte) is Browser AI agent that allows you to run browser automation scripts using AI models. It is a web agent framework built for speed, cost-efficiency, scale and reliability. You can use the framework to automate tasks on webpages, test functionality, extract data and verify any specific behavior on the webpage, just like a normal user would do. ## Running Notte Browser Agent tasks with TestingBot Notte allows you to specify a `CDP` endpoint, enabling it to connect to remote browser instances. To run Notte Browser Agent tasks on TestingBot, you can use the following steps and example code to get started: - `pip install notte litellm[proxy]` - Add your OpenAI or Gemini API credentials to the `.env` file: GEMINI_API_KEY="..." import notte from dotenv import load_dotenv load_dotenv() cdp_url = "wss://cloud.testingbot.com?key={key}&secret={secret}&browserName=chrome&browserVersion=latest" with notte.Session(cdp_url=cdp_url) as session: agent = notte.Agent(session=session, reasoning_model='gemini/gemini-2.5-flash', max_steps=30) response = agent.run(task="extract pricing plans from https://testingbot.com") Replace the `key` and `secret` with your TestingBot credentials. You can find more CDP options on [this page](https://testingbot.com/support/web-automate/puppeteer/options). When you run this example, a remote browser session will be started on TestingBot. Notte will use the Gemini LLM to interact with the remote browser and run the task you specified. By using TestingBot as the CDP endpoint, you can run Notte Browser Agent tasks on any of the available browsers in the TestingBot cloud, with speed, scale and reliability. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/chat # What is TestingBot AI Chat? TestingBot AI Chat is an innovative, codeless test automation tool that harnesses Generative AI and Large Language Models (LLMs) to let users interact with an AI agent in a chat-based interface. Instead of writing complex scripts or manually locating elements, simply type a prompt and the AI agent will operate a remote browser in real time. Your prompts can be transformed into automated test cases, allowing you to reuse them for continuous testing of your website or web application. Additionally, the AI agent can generate Selenium WebDriver, Playwright or Puppeteer test scripts based on its recorded interactions with the remote browser. To get started, upgrade your account and go to the [TestingBot member dashboard](https://testingbot.com/members). Click **AI Chat** in the left-hand menu to launch the AI Chat interface. https://www.youtube.com/embed/dEu7sKL0pMo?si=vaAP1L51M37z244y&rel=0 ## Example Prompts Below are some example prompts that you can use with TestingBot AI Chat: - Navigate to https://cnn.com and click on the first article. Verify that it loads correctly. Generate a Playwright test for this. - Go to https://testingbot.com/pricing and click on the Enterprise plan. Verify that the pricing details are correct. Generate a Puppeteer test for this. - Open a new tab and go to https://github.com. Search for "TestingBot" and click on the first result. Verify that the page loads correctly. Generate a Selenium WebDriver test for this. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/codeless # AI Codeless Web Testing TestingBot provides AI solutions for QA and developers to automate their tests and other tasks. Simply instruct our AI agent what to test and the AI agent will create and run tests against your website on regular intervals, alerting you if a test fails. Enter a URL and a prompt to instruct the AI agent what to test. The AI agent will run the test on a real browser in the TestingBot cloud. When an error is detected, the AI agent will alert you. Instead of generating test code from ChatGPT or Claude, you can instruct the AI agent to run tests based on natural language prompts. Unlike traditional test scripts, which can break as soon as the website's UI changes, AI-driven tests dynamically interpret your instructions each time they run. This ensures your tests remain adaptable and up-to-date, even as the website evolves. ## Getting Started To get started, please go to the [Codeless Testing](https://testingbot.com/members/lab) section and click the **Create a new AI test** button. [Create a new AI test](https://testingbot.com/members/lab) ![Add AI test](https://testingbot.com/assets/support/ai/codeless/create_test-d1486a45a5a31b82ae154681a1591bdf167500f8def01722e2d61abb6858559e.png) ### Create a new test You will see the form below, where you can add a name for the test and the webpage you want to start the test with. In the textarea you can write the test prompt in your own language. You can find example prompts in the next [prompts section](https://testingbot.com#prompts). ## Prompts The AI agent will run tests based on the prompts you provide. A prompt is a set of instructions for the AI agent to follow. We recommend keeping test prompts as concise as possible. For example, you can instruct the AI agent to: - Click on a button - Fill in a form - Test a checkout flow - Verify that an element is visible or not visible - Verify that an element contains specific text - Verify that an element does not contain specific text - Verify that an element has or does not have a specific attribute ### Example Prompts Below are some example prompts you could use to test a website: #### User Authentication & Account Management - Click on the "Sign In" button and verify that the login form appears. - Try logging in with an incorrect password and confirm that an error message appears. #### Forms & Input Validation - Fill in the registration form with valid data and submit it. - Try submitting the registration form without entering required fields and verify that validation errors appear. - Enter an invalid email format and check that an error message is displayed. #### Navigation & UI Elements - Click on the "Home" link in the navigation menu and ensure it redirects correctly. - Open the mobile menu and confirm that all expected links are visible. - Scroll down the homepage and check that the footer loads correctly. - Hover over the dropdown menu and verify that all submenu items appear. #### E-Commerce & Payment Testing - Add a product to the cart and verify that the cart updates. - Enter invalid credit card details and ensure an error message appears. #### Content & Accessibility - Check that all images on the homepage load properly. - Verify that all links on the website are clickable and lead to the correct pages. - Use keyboard navigation to tab through elements and ensure accessibility compliance. - Enable dark mode (if available) and confirm that the UI adjusts correctly. - Resize the browser window and confirm that the website is responsive. #### Performance & Security - Try opening the website in an incognito window and verify that session-based content does not persist. - Attempt to submit a form with script injection and confirm that it is sanitized. - Check if the website forces HTTPS and does not allow unsecured connections. #### Multilingual & Localization Testing - Switch the website language to French and confirm that all text updates correctly. - Change the currency on the pricing page and verify that the prices are updated. ## Browsers You can select one or more browsers to run your tests on. The AI agent will run the tests on the selected browsers. Run your tests on the latest versions of Chrome and Edge, on Windows and Linux. ![Test on Browsers with AI](https://testingbot.com/assets/support/ai/browsers-0755c758094f63992df0c601d5083f6d1990c3dc56af52baf404da9e4a06b8d3.png) ## Schedule Indicate when and at which interval, you would like to run the test. You can choose to run the test once, on a daily basis, weekly, or repeat every xx minutes/hours. ![Schedule AI browser tests](https://testingbot.com/assets/support/ai/schedule-6ba4a52ae1422505b0f905a58d5aa486c51948981cb6de822d9a4f6ca0238d89.png) ## Alerting When a test fails, you can choose to be alerted via e-mail, API call (webhook) or SMS text message. ![Schedule AI browser alerts](https://testingbot.com/assets/support/ai/alerting-5f059647c254b9279372ad0b1e23f3319721d940595838cb56ec0a0c1834bd1a.png) ## API You can use the TestingBot REST-API to [create AI tests from prompts](https://testingbot.com/support/api#createtest). Create one or more tests with your prompt, assign browsers and set a schedule. Use [webhooks](https://testingbot.com/support/integrations/webhooks) to get notified of the results. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/ai/mcp # What is TestingBot MCP? The TestingBot MCP server (Model-Controller-Processor) is a service that allows AI agents and Large Language Models (LLMs) to interact with TestingBot’s testing infrastructure and features through natural language prompts. You can manage your TestingBot tests, view test results, run tests, manage team members and more by simply sending natural language commands to your AI agent connected to the MCP server. ## Features The TestingBot MCP server offers a range of features to enhance your testing experience with your favorite AI tools such as Claude, Cursor, VS Code and more. You can simply issue commands, request information, and manage your TestingBot account using natural language. - **Natural Language** : Manage tests, team members, tunnels and more using simple natural language commands. - **Test Result Analysis** : Retrieve test results and generated assets through conversational queries. - **Team Collaboration** : Manage team members and permissions using AI-driven commands. - **Storage** : Manage and upload native mobile apps for testing on physical devices. - **CDP sessions** : Start and manage CDP sessions for browser automation through natural language. ### How does it work? The MCP server will run as a local process on your machine. It will receive natural language commands from your AI agent or LLM and translate these into API calls to TestingBot's services. The response is then returned back to the AI client in a conversational format. ## Getting Started To get started with the TestingBot MCP server, follow the steps below. ### 1-click installers We provide 1-click installers for Visual Studio Code and Cursor. Click on one of the options below to automatically configure the TestingBot MCP server: #### Visual Studio Code Install the TestingBot MCP server for Visual Studio Code with a single click. This will automatically configure the MCP settings in your VS Code environment. [Install for VS Code](https://testingbot.com/mcp/install?client=vscode) #### Cursor Install the TestingBot MCP server for Cursor with a single click. This will automatically configure the MCP settings in your Cursor editor. [Install for Cursor](https://testingbot.com/mcp/install?client=cursor) #### Claude Install the `mcp-server.mcpb` file from the [MCP releases page](https://github.com/testingbot/mcp-server/releases). Claude will automatically set up the TestingBot MCP server. You will need your TestingBot API key and secret to complete the setup. You can find these in your [account settings](https://testingbot.com/members/user/security). ### Manual Installation If you prefer to install the MCP server manually, or if you're using a different AI client, you can follow the instructions below: #### Prerequisites - Node.js 18 or higher - TestingBot API key and secret - An MCP-compatible client (Claude Desktop, VS Code, Cursor, etc.) [VS Code](https://testingbot.com#)[Cursor](https://testingbot.com#)[Claude](https://testingbot.com#)[GitHub (Manual)](https://testingbot.com#) Follow these steps to install and set up the TestingBot MCP server for Visual Studio Code: 1. Open Visual Studio Code. 2. Open the command palette by pressing `Ctrl+Shift+P` (or `Cmd+Shift+P` on macOS). 3. Type in "MCP: Add Server" 4. A dropdown will appear with options. Choose the NPM Package method. 5. You can now enter the NPM package: `@testingbot/mcp-server` 6. You will see a confirmation screen requesting to install the TestingBot MCP server. 7. Click "Install". Enter your TestingBot Key and Secret which you can obtain from [the member area](https://testingbot.com/members/user/edit). Follow these steps to install and set up the TestingBot MCP server for Cursor: 1. Create or open the file `.cursor/mcp.json`. 2. Add the configuration to the `mcp.json` file: { "mcpServers": { "testingbot": { "command": "npx", "args": ["-y", "@testingbot/mcp-server@latest"], "env": { "TESTINGBOT_KEY": "", "TESTINGBOT_SECRET": "" } } } } 3. Restart Cursor - the MCP server will now be available. Follow these steps to install and set up the TestingBot MCP server for Claude: 1. Create or open the file `claude_desktop_config.json`. 2. Add the configuration to the `claude_desktop_config.json` file: { "mcpServers": { "testingbot": { "command": "npx", "args": ["-y", "@testingbot/mcp-server@latest"], "env": { "TESTINGBOT_KEY": "", "TESTINGBOT_SECRET": "" } } } } 3. Restart Claude (Desktop) - the MCP server will now be available. You can install the MCP server locally from the [TestingBot MCP GitHub repository](https://github.com/testingbot/mcp-server). ## Example prompts Here are some example prompts you can use with the TestingBot MCP server: ### Manual Testing > "Start a live testing session on Chrome latest with Windows 11 for https://example.com" > "Open https://myapp.com on iPhone 14 with iOS 16 for manual testing" ### Browsers & Devices > "List all available browsers and versions" > "Show me all available real devices for mobile testing" ### Test Management > "Show me my last 20 tests" > "Mark test abc123 as passed" ### Screenshots > "Take a screenshot of https://example.com on the latest Chrome and Firefox on Windows 11" > "Screenshot https://testingbot.com on a iOS 26 mobilesafari simulator" ### TestingBot Storage > "Upload https://example.com/app.ipa to TestingBot" ### Team Management > "Show me all team members" ### CDP Session > "Create a CDP session on Chrome latest with Windows 11" ### TestingBot Tunnel > "Show me all active tunnels" ## FAQ ##### Is this MCP server compatible with various AI models or specific to a particular provider? MCP servers are LLM-agnostic, which means they work with any LLM model that supports the Model Context Protocol. ##### Is the information that I feed through MCP used to train? No, the MCP server does not send any information to an LLM. It's the LLM that is requesting information from the MCP server. The MCP server will perform API calls to the TestingBot API. ##### How does authentication to TestingBot happen? When configuring the MCP server, you will need to specify the TestingBot Key and Secret which you can obtain from the member area. These credentials are stored on your local machine, it's the credentials that the MCP Server uses to communicate with the TestingBot API. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-live # Manual Testing - [Is usage limited in terms of minutes or users?](https://testingbot.com#usage) - [What do I get with a Free Trial?](https://testingbot.com#trial) - [Is manual testing on TestingBot secure?](https://testingbot.com#secure) - [How can I test my website on my own computer or network?](https://testingbot.com#tunnel) - [Do I need to download any software?](https://testingbot.com#software) - [Which browsers and platforms do you provide for testing?](https://testingbot.com#browsers) - [What kind of Developer Tools are pre-installed on the browsers?](https://testingbot.com#tools) - [Is audio enabled during testing?](https://testingbot.com#audio) - [Can I embed manual app/web testing in my own website or product?](https://testingbot.com#embed) ## Is usage limited in terms of minutes or users? With an [upgraded plan](https://testingbot.com/pricing) you can use as many minutes as you like with as many friends and co-workers as you wish. There are no limits with manual browser testing. Trial accounts can use up to 60 manual testing minutes. ## What do I get with a Free Trial? Trial accounts can use up to 60 free minutes in manual testing. Once you open a browser in our cloud, you'll get 5 minutes of unlimited access to the browser. With an upgraded plan, you'll enjoy unlimited minutes of manual testing, without any restrictions. ## Is manual testing on TestingBot secure? None of your data is stored in our cloud, for each test you receive a VM with a pristine environment. VMs use up-to-date security patches and are located in a secure datacenter with firewalls. ## How can I test my website on my own computer or network? You can use TestingBot to test your staging website in our cloud. For example: you're working on a new feature and want to make sure it looks and behaves ok in all browsers, before releasing it to the public. With our [Tunnel](https://testingbot.com/support/tunnel) you can easily and securely connect your network with our cloud. ## Do I need to download any software? You do not need to download any software or plugins. In our member area, you can pick on which browser you'd like to test. Once we've booted a Virtual Machine for you, you can control the machine from inside your browser. You can for example control an IE9 browser located in our cloud from inside your own Chrome browser. ## Which browsers and platforms do you provide for testing? We provide the latest and most used browsers, versions and platforms. Ranging from IE6-IE11 on Windows, to Chrome on Linux, or Safari 14 on Mac to Firefox 81 on Windows 10. See our full [list of supported browsers](https://testingbot.com/support/web-automate/browsers). ## What kind of Developer Tools are pre-installed on the browsers? All browsers have their built-in developer tools enabled by default. ## Is audio enabled during testing? Audio is available during all manual tests on Desktop machines and simulators/emulators. Audio is available on manual physical Android device testing, for devices with Android 12 and higher. On physical iOS devices, audio is available on a select number of devices, with iOS version higher than 14. ## Can I embed manual app/web testing in my own website or product? Yes, you can embed TestingBot's manual testing interface in your own website or product using an iframe. 1. Start a manual session through an API call. 2. Fetch the `sessionId` of the session and generate an `authentication hash`. 3. Pass the `sessionId` and `authentication hash` to a liveview URL and embed it with an iframe. const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: process.env.TESTINGBOT_KEY, api_secret: process.env.TESTINGBOT_SECRET }); const options = { capabilities: { browserName: 'chrome', browserVersion: 'latest', platform: 'WIN11', 'tb:manual': true, } }; const session = await tb.createSession(options); const sessionId = session.session_id; const authHash = tb.getAuthenticationHashForSharing(sessionId); const liveViewUrl = `https://testingbot.com/tests/${sessionId}/live?auth=${authHash}`; You can then embed the live view URL in an iframe as follows: You will have a fully functional manual testing interface embedded in your own application. --- URL: https://testingbot.com/support/web-live/extension # Browser Extension - [What is the TestingBot Browser Extension?](https://testingbot.com#usage) - [Installation](https://testingbot.com#installation) - [Using the Browser Extension](https://testingbot.com#usage) ## What is the TestingBot Browser Extension? The TestingBot Browser Extension can be installed on your [Chrome](https://chrome.google.com/webstore/detail/testingbot/nhjmiaiamlfblfagaodhkeabfbnmdmff) or [Firefox](https://addons.mozilla.org/addon/testingbot/) browser, for free. Once installed, you can visit any website with your own Chrome or Firefox browser, and click the TestingBot extension icon. A window will pop up, allowing you to choose on which remote browser you want to test the current page on. Upon selecting a browser, the current page will be available for testing on a remote TestingBot browser. For example, you are using Chrome but want to make sure that the website you are currently seeing looks and functions correctly on a macOS Safari browser. With the extension, you can simply choose the remote browser configuration. You will be redirected to a live view of the remote browser, where you can use your mouse and keyboard to interact and test the webpage. ## Installation The TestingBot Browser Extension is currently available for [Chrome](https://chrome.google.com/webstore/detail/testingbot/nhjmiaiamlfblfagaodhkeabfbnmdmff) and [Firefox](https://addons.mozilla.org/addon/testingbot/). Simply click the **Add Extension** button to add the extension to your browser. A TestingBot icon will now appear in your browser's navigation bar. You can pin the extension to make sure it remains visible at all times. ## Using the Browser Extension After installation, you can simply navigate to any website you want to test. Click the TestingBot extension icon to open a popup with browser choices. ![TestingBot Browser Extension](https://testingbot.com/assets/support/manual/extension-201001ac8ef0e3e987d2163148ebaff5c6062c9f3dbc2c6c0077cd16b1e4dd15.webp) Make sure you are logged in to TestingBot while using the extension. --- URL: https://testingbot.com/support/web-live/chromeos # ChromeOS Manual Testing TestingBot gives you the ability to test your website on a remote ChromeOS device emulator, such as a Chromebook. Simply enter the URL of the website you want to test and choose between 3 different ChromeOS configurations: - ChromeOS Small: 1366x768 - 160dpi - ChromeOS Medium: 3840x2160 - 320dpi - ChromeOS Large: 1920x1080 - 160dpi ## Starting a live ChromeOS session Simply [start a new manual session](https://testingbot.com/members/manual/new) by clicking the Android category and choosing one of the three ChromeOS configurations. A remote session will be started and you will be able to interact with the ChromeOS device emulator with your own mouse and keyboard. An audio stream will be started, so you can hear the sounds from the ChromeOS device emulator. ![Test on ChromeOS](https://testingbot.com/assets/support/manual/chromeos-7d003af4076458e52d6a4381b4bf2fee154591253bfe1070e9af5583c4256cac.jpg) ## Enabling/disabling Dark Mode You can easily enable or disable Dark Mode in the ChromeOS emulator by clicking the "Device Settings" button in taskbar, then toggling the "Enable Dark Mode" switch. ## Taking screenshots To take a live screenshot of the current ChromeOS session, simply click the "Photo" button in the taskbar. This will capture the current view and open the screenshot in a photo editor, which you can use to annotate or modify the screenshot, before downloading or sharing it. ## Change GPS You can use the "GPS" button in the taskbar to change the GPS location of the ChromeOS device emulator. This is useful for testing location-based features on your website. --- URL: https://testingbot.com/support/app-live # Live Mobile App Testing Take control over our real devices with your mouse and keyboard, straight from your own browser, without having to install any plugin or program. Simply upload your iOS or Android app to TestingBot, [pick the device](https://testingbot.com/support/app-automate/devices) you want to test on, and TestingBot will give you a live session with the real device. ## Uploading a mobile App You can upload your mobile app either through the TestingBot UI or via an [API call](https://testingbot.com/support/api#upload). ### Upload via the UI To upload a mobile app through the TestingBot UI, simply go to the member dashboard and: - Click **Live App Testing** - Under **Select Source** click **Uploaded Apps** - Either drag your mobile application on the page, or click **Upload App** to browse for the file Currently we accept these file formats: - `.aab`, `.apk` for Android - `.ipa`, `.zip` for iOS ![upload app through UI](https://testingbot.com/assets/support/mobile/manual/upload-ui-4cc682c6ba74f6783fb5780f5e6e010c045d2ee69fa7459927f9f2d5db0a5b5f.jpg) ## Deleting a mobile App To delete a mobile app, you can use the TestingBot UI or use our [REST API](https://testingbot.com/support/api#filedelete). ### Delete via the UI To delete a mobile app through the TestingBot UI, simply go to the member dashboard and: - Click **Live App Testing** - Under **Select Source** click **Uploaded Apps** - Click the trash icon in the bottom right corner of the list - Select one or more apps you wish to delete - Click **Delete Apps** ![Delete App](https://testingbot.com/assets/support/mobile/manual/delete-1-a196012383d2e00587197d989ef961f26029304d49389a016d363292ec01cbe7.jpg) ![Delete App](https://testingbot.com/assets/support/mobile/manual/delete-2-d6222cd6c9c5cfbef507b6c586c6fc4a56a5d156308b1b3337d4f1ae034eccf4.jpg) ## Selecting a Mobile Device Once you've selected a mobile app, you will need to select the device you want to run tests on. You can choose to select a Virtual Device or a Real Device by using the navigation tabs on the page. ### Real Devices To use a Real Device, click the [Real Device Testing](https://testingbot.com/members/apps/devices/new) tab. - Click an available device from the devices list - Make sure to select an iOS device if you've selected an iOS app (`.ipa`), or an Android device if you've selected an Android app (`.apk`) - Click the **Start** button ### Virtual Devices To use a Virtual Device, click the [Emulator & Simulator Testing](https://testingbot.com/members/apps/new) tab. - Select an app you've uploaded, or the sample Android/iOS TestingBot app. - Click the Android or iOS tab in the virtual device list - Select an iOS simulator if you've selected an iOS app (`.ipa`), or an Android emulator if you've selected an Android app (`.apk`) - Click the **Start** button ### Time Limits and Timeouts for Live App Testing - Live tests will last a maximum of 5 minutes at a time for trial users. - Live tests for paid users will timeout after 15 minutes of inactivity ## Live Test Interface Below is some more information on the various functions that the TestingBot Live App Testing UI provides. Icon | Name | Description || | Switch Device | Change to a different device. This will start a new session, you will lose the session with the current device. | | | Zoom | Zoom in or out. This will make the device's screen appear larger or smaller. This only affects the view in your browser, it does not change anything on the device itself. | | | Rotate | Rotates the device. Either from PORTRAIT to LANDSCAPE or vice-versa. | | | Screenshot | Takes a screenshot from the device. A screenshot editor will appear, allowing you to annotate the image. Download the screenshot with the download button. | | | Copy/Paste | Copy or paste from or to the device. If you've selected the copy/paste permission in your browser, TestingBot will automatically keep your local and remote clipboard in sync. | | | DevTools | This will open the developer tools for the device. Retrieve realtime logs from the device. Use the **Inspector** functionality to drill down in the view hierarchy to copy element locators (such as XPath). | | | GPS Location | Set a (new) mock location for the GPS of the device. If your app uses GPS functionality, it will receive this mock location | | | Locale | Set a new locale for the entire device. Useful if your app is multilingual. Test your app in different languages. | | | Device Settings | Change various device settings. Switch between light and dark mode instantly. | | | Stop Session | Stops the current session. Logs and a video of the test will be available in the TestingBot member area. | ## Audio Audio is available during manual mobile app testing, for certain devices. ### Virtual Devices Audio is available for all Android emulators and iOS Simulators. TestingBot will stream the audio generated by the virtual device to your web browser. ### Physical Devices Android devices with Android version 12 and higher will stream the audio to your browser, you will hear all the audio generated on the device. For iOS devices with iOS version 14 and higher, you will hear the audio from the device in realtime. Older physical devices do not have the audio streaming capabilities. These will only stream a live video view of the device. ## Device Logs TestingBot provides a real-time stream of the device logs during the manual live session. You can switch between these device log levels: - `VERBOSE` (default) - `DEBUG` - `INFO` - `WARNING` - `ERROR` You can use the search input bar to search between the generated logs. Icon | Functionality || | The download icon allows you to download the entire device logs generated thus far, without any filtering. | | | The trash icon will clear the history of the logs. Only new log entries will be added to the realtime view. | ## Testing Local Websites/Apps With our [TestingBot Tunnel](https://testingbot.com/support/tunnel) you can easily and securely connect your local computer/network with TestingBot's Real Devices. #### Known Limitations - **Localhost testing does not work on iOS**. Due to an iOS Restriction, it is currently not possible to run tests against `http(s)://localhost` with TestingBot Tunnel. A possible workaround would be to change the hosts file on the machine running TestingBot Tunnel, and add a custom hostname (for example `mylocalwebsite` and the IP address `127.0.0.1`). Then configure your tests to use `http(s)://mylocalwebsite/...` instead of localhost. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-live/apple-pay # Testing Apple Pay Apple Pay, developed by Apple Inc., serves as a mobile payment and digital wallet service enabling transactions through various Apple devices, such as iPhones and iPads. Testing with Apple Pay comes with challenges. This document aims to clarify some methods that are available for testing with iOS and Apple Pay. There are important differences between Apple Pay on Real Devices and iOS Simulators. The iOS Simulator has the following limitations: - The simulator only targets the front-end integration of Apple Pay and does not test the back-end integration. - You can not add payment cards to the wallet on iOS simulators. So no Apple Pay sandbox testing cards, or any other real credit card. - It is not possible to test the Apple Pay in-web flow. - It is possible to test the Apple Pay in-app flow, but the Apple Pay in-app flow will not work the same way as with a real iOS device. It will not return a payment token and will not properly process a payment. ## Apple Pay on Real Private Devices TestingBot provides [private iOS devices](https://testingbot.com/enterprise/private-device-cloud), which are able to use Apple Pay. To make Apple Pay work on TestingBot's real private devices, please follow the steps below: 1. Follow Apple's documentation to [enable Apple Pay](https://developer.apple.com/documentation/passkit/apple_pay/setting_up_apple_pay) 2. Set up Apple Pay integration in your iOS app, using the Apple documentation. 3. Register your Merchant ID in your Apple developer account. 4. Set up an Apple sandbox tester account. See the [Apple Sandbox documentation](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/create-sandbox-apple-ids/) for more information. 5. Build your ipa file. Apple Pay will not work with enterprise certificates, which means it will not work by default on TestingBot's private devices. You will need to add the `udid` (iPhone/iPad unique id) of each private device assigned to you, to your Apple provisioning profile. - Log in to [Apple's Developer Account](https://developer.apple.com/account/resources/identifiers/list) - Click [Add Device](https://developer.apple.com/account/resources/devices/add) - Type in a device name and the UDID that you received from TestingBot. - Save the device. - Now add the new device to your [Provisioning Profile](https://developer.apple.com/account/resources/profiles/list) ### Passcode One of the requirements to use Apple Pay, is that a passcode needs to be set on the device. Make sure that you set a passcode on your private iOS device. TestingBot cleans every private device after each test session. You will need to configure your Apple Pay Sandbox Testing account, including a passcode and sandbox cards, every time you want to test Apple Pay on a real iOS device. If you want to disable this automated cleaning process, please [reach out](https://testingbot.com/contact/new). ## Apple Pay on iOS Simulators iOS Simulators offer a feature where you can authorize Apple Pay by clicking a button in the Simulator's menu bar. - Navigate to a point in your app where a payment sheet is visible. - Click **Features** , then enable **Authorize Apple Pay** , or use the key combination (Command+SHIFT+A). ## Apple Sandbox Test Cards You can find a list of Test Cards and their details on [Apple Pay's Sandbox Testing documentation page](https://developer.apple.com/apple-pay/sandbox-testing/). These test cards include Discover, Master Card, American Express, VISA and others. There are cards available for the USA, Europe, China and even Test Cards for Point of Sale Systems. To use these, simply open the **Wallet** application on your iOS device and add the card number and expiration date. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-live/chromeos # ChromeOS Manual App Testing With TestingBot, you can upload your native Android app and test it on a remote ChromeOS device emulator, such as a Chromebook. After you upload your app, simply choose one of the three ChromeOS configurations to start testing: - ChromeOS Small: 1366x768 - 160dpi - ChromeOS Medium: 3840x2160 - 320dpi - ChromeOS Large: 1920x1080 - 160dpi ## Starting a live ChromeOS session To get started, make sure you uploaded a `.apk` file on the [manual app session](https://testingbot.com/members/apps/new) page. Then, click one of the three ChromeOS configurations to start a new manual session. A remote session will be started and you will be able to interact with the ChromeOS device emulator with your own mouse and keyboard. An audio stream will be started, so you can hear the sounds from the ChromeOS device emulator. ![Test an app on ChromeOS](https://testingbot.com/assets/support/manual/chromeos-app-1e807772235f4f2af5ee949006a49b10bca80b6ea7f4f40b6118aa5c21124d56.jpg) ## Enabling/disabling Dark Mode You can easily enable or disable Dark Mode in the ChromeOS emulator by clicking the "Device Settings" button in taskbar, then toggling the "Enable Dark Mode" switch. ## Taking screenshots To take a live screenshot of the current ChromeOS session, simply click the "Photo" button in the taskbar. This will capture the current view and open the screenshot in a photo editor, which you can use to annotate or modify the screenshot, before downloading or sharing it. ## Change GPS You can use the "GPS" button in the taskbar to change the GPS location of the ChromeOS device emulator. This is useful for testing location-based features on your website. --- URL: https://testingbot.com/support/api # TestingBot API Documentation Access and modify all your TestingBot data through our comprehensive REST API. Build powerful integrations and automate your testing workflows. All API responses are returned in JSON format. API Endpoint: `https://api.testingbot.com` Current Version: v1 ## API Clients There are several open source client libraries available to easily interact with the TestingBot API: - [NodeJS](https://github.com/testingbot/testingbot-api) - [Python](https://github.com/testingbot/testingbotclient) - [Java](https://github.com/testingbot/testingbot-java) - [Ruby](https://github.com/testingbot/testingbot_ruby) - [PHP](https://github.com/testingbot/testingbot-php) ## Authentication You can authenticate to our TestingBot API by providing your API key and API secret which you can obtain in the [member area](https://testingbot.com/members). Authentication to the API needs to happen via [HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication). All requests must be made to our endpoint via HTTP. You must authenticate for all API requests, except for `List of browsers`. ## List of browsers This call will return a list of browsers our grid currently supports. No authentication is required for this API call. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) curl "https://api.testingbot.com/v1/browsers" require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_browsers TestingbotREST restApi = new TestingbotREST(key, secret); ArrayList browsers = restApi.getBrowsers(); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getBrowsers(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.information.get_browsers() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const browsers = await api.getBrowsers(); Optional Arguments: - (string) **type** - either "webdriver" or "rc" Response: [{"selenium_name":"IE8","name":"iexplore","version":8,"platform":"WINDOWS","browser_id":1,"long_version":8}, {"selenium_name":"FF7","name":"firefox","version":7,"platform":"WINDOWS","browser_id":22,"long_version":7}] ## Access your user info This call will return the data associated to your account. You can edit this data by issueing a PUT request to our API. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/user" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_user_info TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.getUserInfo(); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getUserInfo(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.user.get_user_information() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const userInfo = await api.getUserInfo(); Arguments: None required Response: { "first_name": "Steven", "last_name": "King", "seconds": 17745, "last_login" : "2026-01-16 16:40:49 UTC", "plan" : "small", "max_concurrent": 10, "max_concurrent_mobile": 2, "company":"companyName", "street":"companyStreet", "city":"companyCity", "country":"companyCountry", "vat":"ifInEurope" } ## Edit your user info This call will return the data associated to your account. You can edit this data by issueing a PUT request to our API. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/user" \ -X PUT \ -d "user[first_name]=new" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.update_user_info({ "first_name" => 'new' }) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.updateUserInfo(TestingBotUser); $api = new TestingBot\TestingBotAPI($key, $secret); $api->updateUserInfo(array('first_name' => 'new')); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.user.update_user_information() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const newUserData = { first_name: 'new' } await api.updateUserInfo(newUserData); Arguments: - (string) **first\_name** - (string) **last\_name** Response: { "success" : true, "user" : { "first_name": "new", "last_name": "King", "seconds": 17745, "last_login" : "2011-08-06T16:47:04Z" } } ## Get Team Info If you are part of a team, you can fetch information regarding the team with this API call. The response will include the maximum allowed concurrency for both VM based testing and physical mobile device testing. Next to that, the response will include the current usage of the entire team, for both VM based testing and physical mobile device testing. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/team-management" \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const teamInfo = await api.getTeam(); Response: { "concurrency":{ "allowed":{ "vms": 10, "physical": 2 }, "current":{ "vms": 4, "physical": 1 } } } ## Get users in your team Retrieve all users that are part of your team. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/team-management/users" \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const users = await api.getUsersInTeam(); Response: { "data":[ { "id":337, "first_name":"test", "last_name":"user", "seconds":12000, "last_login":"2021-05-12T19:37:35.000Z", "plan":"Free Trial", "max_concurrent":2, "max_concurrent_mobile":2, "company":"", "street":"", "city":"", "country":"", "vat":null, "read_only":false, "roles":[], "current_vm_concurrency":0, "current_physical_concurrency":0 } ], "meta":{ "offset":0, "count":1, "total":1 } } The `roles` field indicates if you have one of the roles in the team: - ADMIN - USER ## Retrieve a specific user in your team Retrieve a specific user that is part of your team. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/team-management/users/:id" \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const user = await api.getUserFromTeam(userId); Arguments: - (string) **:id** - a unique string identifying the user Response: { "id":337, "first_name":"test", "last_name":"user", "seconds":12000, "last_login":"2021-05-12T19:37:35.000Z", "plan":"Free Trial", "max_concurrent":2, "max_concurrent_mobile":2, "company":"", "street":"", "city":"", "country":"", "vat":null, "read_only":false, "roles":[], "current_vm_concurrency":0, "current_physical_concurrency":0 } The `roles` field indicates if you have one of the roles in the team: - ADMIN ## Create a user in your team Adds a new user to your team. You can use this API call to add TestingBot accounts for colleagues or people in your team. Usage of this API call requires an upgraded account and `ADMIN` role. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST -u -u key:secret \ https://api.testingbot.com/v1/team-management/users --header 'Content-Type: application/json' --data-raw '{ "first_name": "Bruno", "last_name": "Mars", "email": "bmars@gmail.com", "password": "$bmaRs*RULES" }' const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const userData = { 'user[first_name]': 'John', 'user[last_name]': 'Doe', 'user[email]': 'john@example.com' }; const result = await api.createUserInTeam(userData); Arguments: - (string) **:first\_name** - (string) **:last\_name** - (string) **:email** - (string) **:password** Response: { "id":337, "first_name":"Bruno", "last_name":"Mars", "seconds":12000, "last_login":"2021-05-12T19:37:35.000Z", "plan":"Free Trial", "max_concurrent":2, "max_concurrent_mobile":2, "company":"", "street":"", "city":"", "country":"", "vat":null, "read_only":false, "roles":[], "current_vm_concurrency":0, "current_physical_concurrency":0 } ## Update a user in your team Updates details for a user in your team. Usage of this API call requires an upgraded account and `ADMIN` role. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X PUT -u -u key:secret \ https://api.testingbot.com/v1/team-management/users/:id --header 'Content-Type: application/json' --data-raw '{ "first_name": "Bruno", "last_name": "Mars", "email": "bmars@gmail.com", "password": "$bmaRs*RULES" }' const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const userData = { 'user[first_name]': 'Jane', 'user[last_name]': 'Smith' }; const result = await api.updateUserInTeam(userId, userData); Arguments: - (string) **:id** - (string) **:first\_name** - (string) **:last\_name** - (string) **:email** - (string) **:password** - (string) **:credits** - how many credits (in seconds) this user for running tests on VMs - (string) **:device\_credits** - how many credits (in seconds) this user for running tests on physical devices - (string) **:concurrency** - how many tests this user is able to run in parallel on VMs - (string) **:concurrencyPhysical** - how many tests this user is able to run in parallel on physical devices Response: { "id":337, "first_name":"Bruno", "last_name":"Mars", "seconds":12000, "last_login":"2021-05-12T19:37:35.000Z", "plan":"Free Trial", "max_concurrent":2, "max_concurrent_mobile":2, "company":"", "street":"", "city":"", "country":"", "vat":null, "read_only":false, "roles":[], "current_vm_concurrency":0, "current_physical_concurrency":0 } ## Reset credentials for a specific user in your team This API call allows you to reset the secret credentials for a user in your team, which are required to connect to the TestingBot grid. Usage of this API call requires an `ADMIN` role. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST -u -u key:secret \ https://api.testingbot.com/v1/team-management/users/:id/reset-keys' const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const result = await api.resetCredentials(userId); Arguments: - (string) **:id** Response: { "success":true, "client_key":"d69e0800xc32ed2f059b7a630ee255b" } Only the `client_key` will be returned. The `client_secret` will also be reset, but will only be visible to the user in the member area. ## Retrieve your tests Will return all the tests you have created together with details for every test. You can use the offset and count parameters to paginate your tests. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tests?offset=0&count=10" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_tests(0, 10) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotTest test = restApi.getTests(0, 10); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getJobs(0, 10); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tests.get_tests(offset=0, limit=10) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const tests = await api.getTests({ offset, limit }); Arguments: - (int) **offset** (optional) (default 0) - paginate tests starting from this number - (int) **count** (optional) (default 10, max 500) - number of tests to fetch - (string) **group** (optional) - retrieve tests that belong to this group - (string) **build** (optional) - retrieve tests that belong to this build - (int) **browser\_id** (optional) - retrieve tests that ran with this browser\_id - (string) **skip\_fields** (optional) - skip these fields. For example: ?skip\_fields=logs,thumbs Response: { "data":[ { "created_at":"2011-07-30T23:21:23Z", "completed_at":"2011-07-30T23:22:44Z", "extra":null, "id":3, "name":"MyTest::testTitle", "session_id":"f7903f9e93e74fe1b0e924bf9d2ce9fc", "status_message":"Failed asserting that 1 equals 0.", "device_name": null, "platform_name": null, "status_id": 1, "success":false, "test_environment_id":1, "thumbs":[], "video":"https://s3.amazonaws.com/rectestingbot/sample.mp4", "groups":["testingbot.com"], "browser":"IE8", "browser_version":8, "os":"WINDOWS", "duration":13, "build":"buildid", "logs":{"vm":"https://s3-eu-west-1.amazonaws.com/eulogtestingbot/session.txt"} } ], "meta": { "offset":2, "count":3, "total":789 } } Possible errors: - 404 Not found - test not found ## Specific test info This call will return info for one of your tests. In the example below, the response will contain info for a test with Selenium sessionId 3. You can fetch all the various test sessionIds that belong to you by [fetching your tests](https://testingbot.com#tests). [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tests/:webdriver_session_id" -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_test(webdriver_session_id) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotTest test = restApi.getTest(String webdriver_session_id); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getJob($webdriver_session_id); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tests.get_test(webdriver_session_id) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const test = await api.getTestDetails(webdriver_session_id); Arguments: - (string) **:webdriver\_session\_id** - a unique string identifying your test (= Selenium sessionId) - (string) **skip\_fields** (optional) - skip these fields. For example: ?skip\_fields=logs,thumbs Response: { "created_at":"2011-07-30T23:21:23Z", "completed_at":"2011-07-30T23:22:23Z", "extra":null, "id":3, "name":"MyTest::testTitle", "session_id":"f7903f9e93e74fe1b0e924bf9d2ce9fc", "status_message":"Failed asserting that 1 equals 0.", "device_name": null, "platform_name": null, "success":false, "state":"COMPLETE", "unknown":false, "thumbs":["https://s3.amazonaws.com/euthumbtestingbot/3_f93782fji.jpg"], "video":"https://s3.amazonaws.com/eurectestingbot/sample.mp4", "logs": {"selenium":"https://s3-eu-west-1.amazonaws.com/eulogtestingbot/session.txt"}, "groups":["testingbot.com"], "build": null, "browser":"IE8", "browser_version": 8, "os":"VISTA", "duration":60, "type":"WEBDRIVER", "assets_available": true, "steps": [ { "command":"/session", "arguments":"{\"capabilities\":{\"alwaysMatch\":{\"browserName\":\"chrome\",\"version\":\"108\"},\"firstMatch\":[{}]},\"desiredCapabilities\":{\"platform\":\"WIN8\",\"browserName\":\"chrome\",\"version\":\"108\"}}", "response":"cb7503d4b57a-1df17d3a749a-bb324331da31-167601846491-06317943", "time":1676018469521 } ] } Possible errors: - 404 Not found - test not found ## Update a test This call will update a test. You can use this call to update the success status, add a name or extra data, ... To update a specific test, pass its unique test ID or its Selenium session ID. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tests/:webdriver_session_id" \ -X PUT \ -d "test[success]=1" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) @api.update_test(webdriver_session_id, { :name => new_name, :success => true }) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.updateTest(String webdriver_session_id, Map details); $api = new TestingBot\TestingBotAPI($key, $secret); $api->updateJob($webdriver_session_id, array('name' => 'mytest', 'success' => true)); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(webdriver_session_id, status_message=.., passed=1|0, build=.., name=..) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const testData = { "test[success]" : "1", "test[status_message]" : "test" }; await api.updateTest(testData, webdriver_session_id); Arguments: - (string) **id** - a unique string identifying your test (= Selenium sessionId, a UUID) - (boolean) **test[success]** - indicating if the test was successful - (string) **test[status\_message]** - the status/error message of your test - (string) **test[name]** - the name of your test - (string) **test[extra]** - extra data for this test - (string) **groups=...,...** - a comma-separated string of groups for this test - (string) **build=...** - what build this test belongs to Response: { "success" : true } Possible errors: - 404 Not found - test not found ## Delete test Will delete a specific test, together with possible thumbnails. In the example below, we'll delete a test with id 3. You can fetch all the various test ids that belong to you by [fetching your tests](https://testingbot.com#tests). [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tests/:webdriver_session_id" \ -X DELETE \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.delete_test(webdriver_session_id) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.deleteTest(String webdriver_session_id); $api = new TestingBot\TestingBotAPI($key, $secret); $api->deleteJob($webdriver_session_id); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tests.delete_test(webdriver_session_id) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); await api.deleteTest(webdriver_session_id); Arguments: - (string) **id** - a unique identifier identifying your test Response: { "success":true } Possible errors: - 404 Not found - test not found ## Stop test Will terminate the running test job. This will end the test and mark the test as completed. Any test assets and metadata gathered will be available for download. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tests/:session_id/stop" \ -X PUT \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.stop_test(session_id) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.stopTest(String session_id); $api = new TestingBot\TestingBotAPI($key, $secret); $api->stopJob($session_id); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tests.stop_test(session_id) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); await api.stopTest(webdriver_session_id); Arguments: - (string) **:session\_id** - a unique number identifying your test Response: { "success":true } Possible errors: - 404 Not found - test not found ## Retrieve all builds Will retrieve all builds for your account. A build is a group of tests. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/builds?offset=0&count=10" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_builds(0, 10) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotBuildCollection builds = restApi.getBuilds(int offset, int count); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getBuilds(0, 10); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.build.get_builds(offset=0, limit=10) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const builds = await api.getBuilds(offset, limit); Arguments: - (int) **offset** (optional) (default 0) - paginate tests starting from this number - (int) **count** (optional) (default 10, max 500) - number of tests to fetch Response: { "data":[ { "id" : 4331, "build_identifier" : "first-build", "created_at" : "2016-08-01T11:09:02.000Z", "updated_at" : "2016-08-01T11:09:02.000Z" } ], "meta":{ "offset" : 0, "count" : 10, "total" : 3 } } ## Tests for a build Will return all tests for a single build. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/builds/:buildId" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_build(build_identifier) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotTestBuildCollection tests = restApi.getTestsForBuild(String buildId); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getBuild($buildId); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.build.get_tests_for_build(buildId) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const tests = await api.getTestsForBuild(buildId); Arguments: - (string) **buildId** - a unique string describing the build Response: { "data":[ { "created_at":"2011-07-30T23:21:23Z", "completed_at":"2011-07-30T23:22:44Z", "extra":null, "id":3, "name":"MyTest::testTitle", "session_id":"f7903f9e93e74fe1b0e924bf9d2ce9fc", "status_message":"Failed asserting that 1 equals 0.", "success":false, "thumbs":[], "video":"https://s3.amazonaws.com/rectestingbot/sample.mp4", "groups":["testingbot.com"], "browser":"IE8", "browser_version":8, "os":"WINDOWS", "duration":13, "build":"buildid", "logs":{"browser":"https://s3-eu-west-1.amazonaws.com/eulogtestingbot/session.txt"}, "assets_available": true } ] } ## Delete a build Will delete a build. Does not delete the tests in the build. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/builds/:buildId" \ -X DELETE \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.delete_build(build_identifier) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.deleteBuild(String buildId); $api = new TestingBot\TestingBotAPI($key, $secret); $api->deleteBuild($buildId); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.build.delete_build(buildId) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); await api.deleteBuild(buildId); Arguments: - (string) **buildId** - a unique string describing the build Response: { "successs": true } ## Retrieve all Devices Will fetch all Real Mobile devices, including devices currently in use. The response will include all public devices, and private devices associated to your subscription (if any). [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -u key:secret "https://api.testingbot.com/v1/devices" require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_devices() TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.getDevices(int offset, int count); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getDevices(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.information.get_devices() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const devices = await api.getDevices(); Response: [{ "id":1, "available":true, "model_number":"SM-G950U1", "resolution":"1080x2220", "width":1080, "height":2220, "cpu":"Octa-core (4x2.3 GHz Mongoose M2 & 4x1.7 GHz Cortex-A53)", "name":"Galaxy S8", "platform_name":"Android", "version":"9.0", "multiple_browsers":[ { "id":1727, "name":"chrome", "version":"103.0.5060.129" }, { "id":2133, "name":"firefox", "version":"98.2" }, { "id":2953, "name":"samsung", "version":"13.2.1.70" }, { "id":2954, "name":"opera", "version":"67.1" } ] }, { "id":5, "available":false, "model_number":"MRY42B/A", "resolution":"828x1792", "width":828, "height":1792, "cpu":"ARM - Single-core - 2390Mhz", "name":"iPhone XR", "version":"16.3", "platform_name":"iOS" }] ## Retrieve all Available Devices Will fetch all available Real Mobile devices. The response will include all public devices, and private devices associated to your subscription (if any). [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) % curl -u key:secret "https://api.testingbot.com/v1/devices/available" require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_available_devices() TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.getAvailableDevices(int offset, int count); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getAvailableDevices(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.information.get_available_devices() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const devices = await api.getAvailableDevices(); Response: [{ "id":1, "available":true, "model_number":"SM-G950U1", "resolution":"1080x2220", "width":1080, "height":2220, "cpu":"Octa-core (4x2.3 GHz Mongoose M2 & 4x1.7 GHz Cortex-A53)", "name":"Galaxy S8", "platform_name":"Android", "version":"9.0", "multiple_browsers":[ { "id":1727, "name":"chrome", "version":"103.0.5060.129" }, { "id":2133, "name":"firefox", "version":"98.2" }, { "id":2953, "name":"samsung", "version":"13.2.1.70" }, { "id":2954, "name":"opera", "version":"67.1" } ] }, { "id":5, "available":true, "model_number":"MRY42B/A", "resolution":"828x1792", "width":828, "height":1792, "cpu":"ARM - Single-core - 2390Mhz", "name":"iPhone XR", "version":"16.3", "platform_name":"iOS" }] ## Device Detail Retrieves details for a single device. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/devices/:id" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_device(device_identifier) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotUser user = restApi.getDevice(int deviceId); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getDevice($deviceId); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.information.get_device(deviceId) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const device = await api.getDevice(deviceId); Arguments: - (number) **id** - the numeric id retrieved from the [devices list](https://testingbot.com#devices). Response: { "id":12, "available":true, "model_number":"E", "resolution":"1440x3200", "width":1440, "height":3200, "cpu":"ARM - Quad-core - 1593Mhz", "name":"Galaxy S20", "platform_name":"Android", "version": "10.0", "multiple_browsers":[ {"id":2598,"name":"chrome","version":"101"}, {"id":2919,"name":"firefox","version":"98.2"}, {"id":2957,"name":"samsung","version":"13.2.1.70"}, {"id":2958,"name":"opera","version":"67.1"} ] } ## Take Screenshots With this API call you can request TestingBot to take screenshots of a specific URL with the browsers you specify. **Important:** Please specify the `application/json` Content-Type header and specify the post body as JSON. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -H 'Content-Type: application/json' -X POST "https://api.testingbot.com/v1/screenshots" \ -u key:secret \ -d '{"url":"https://www.google.com", "resolution" : "1280x1024", "browsers" : [{ "browserName" : "chrome", "version" : 134, "os" : "WIN10"}, { "browserName" : "safari", "version" : "17.2", "platformName": "iOS", "deviceName" : "iPhone 15"}, { "browserName" : "chrome", "version" : "15.0", "platformName": "Android", "deviceName" : "Pixel 9"}]}' const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const screenshots = await api.takeScreenshot( 'https://example.com', [{ browserName: 'chrome', version: 'latest', os: 'WIN11' }], '1920x1080' ); Arguments: - (string) **url** - the URL of the page you'd like to take screenshots of - (string) **resolution** - the screenresolution of the OS: - 800x600 - 1024x768 - 1280x960 - 1280x1024 - 1600x1200 - 1920x1200 - 2560x1440 Please see [the available screen resolutions](https://testingbot.com/support/web-automate/selenium/test-options#screenresolution) per platform. - (string) **callback\_url** (optional) - when the screenshots are taken, we can send a JSON formatted post to the callback URL you specify. The JSON body will be identical to the response of the [Retrieve Screenshots API call](https://testingbot.com#retrievescreenshots) - (boolean) **full\_page** (optional) - by default we take a screenshot of the viewport. If you'd like a screenshot of the entire page, set this to 'true'. - (int) **wait\_time** (optional) (default 0) - the time (in seconds) to wait between page load and taking the screenshots - (string) **browsers** - a list of browsers with keys: - (string) **browserName** - the name of the browser (internet explorer, chrome, safari, firefox, ...) - (string) **version** - the version of the browser you require - (string) **os** - the OS where the test should run - (string) **deviceName** - the device name (only for mobile devices) - (string) **platformName** - the platform name (only for mobile devices: iOS or Android) - (boolean) **realDevice** - set to true if you want a screenshot from a [physical device](https://testingbot.com/support/app-automate/devices) Response: { "id" : 3454, "wait_time" : 0, "resolution" : "1280x1024", "url" : "https://www.google.com" } ## Retrieve Screenshots Specify the id of the [take screenshot](https://testingbot.com#takescreenshots) call to query the progress of the screenshots. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/screenshots/:id" -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const screenshotResult = await api.retrieveScreenshots(screenshotJobId); Arguments: - (int) **id** - the id of the screenshot group Response: { "state":"done", "screenshots":[ { "image_url":"https://....", "thumb_url":"https://....", "state":"done", "id":"9c7deea4-6f23-4041-842b-39cccee447fa", "created_at":"2017-10-13T14:47:44.000Z", "os":"SEQUOIA", "browser_name":"googlechrome", "browser_version":"138", "browser_id":1146, "device_name":null, "platform_name":"" } ] } - (string) **state** - represents the current state for screenshot job. Values can be: - **processing** : Not all screenshots have been taken yet. - **done** : All screenshots are available and can be accessed. - **error** : Something went wrong while trying to take the screenshots. - **stopped** : The process of taking the screenshots was stopped by manually clicking the 'stop' button in our UI. - The screenshots object itself: - (string) **image\_url** - location to the actual screenshot (png format) - (string) **thumb\_url** - 100x100 thumb of the actual screenshot - (string) **state** - represents the current state for the screenshot. Values can be: - **processing** : The screenshot has not been taking yet, the test is either queued or running. - **done** : The screenshot has been taken and has been uploaded to our cloud - you can now view the screenshot via **image\_url** or **thumb\_url**. - **error** : Something went wrong while trying to take the screenshot. - **stopped** : The process of taking the screenshot was stopped before a screenshot was taken. This can only be done by manually clicking the 'stop' button in our UI. - (string) **id** - a unique identifier for this screenshot ## Screenshot history Retrieves a list of previous screenshot jobs. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/screenshots" -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const screenshots = await api.getScreenshotList(); This will return a list of screenshot jobs. You can use the `id` of every job to fetch the [screenshots for this job](https://testingbot.com#retrievescreenshots). Arguments: - (int) **offset** (optional) (default 0) - paginate screenshot jobs starting from this number - (int) **count** (optional) (default 10, max 500) - number of screenshot jobs to fetch Response: { "data" : [ { "id":3454, "url":"https://google.com", "resolution":"1280x1024" }, { "id":3452, "url":"https://testingbot.com", "resolution":"1280x1024" }, { "id":3451, "url":"https://yahoo.com", "resolution":"1280x1024" } ], "meta":{ "offset" : 0, "count" : 3, "total" : 3 } } ## TestingBot Tunnel List List of currently active [TestingBot Tunnels](https://testingbot.com/support/tunnel) for your account. You can have up to **3 simultaneous tunnels** running with your account. By issuing a `DELETE` request you can delete/stop any of your tunnels. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tunnel/list" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_tunnels TestingbotREST restApi = new TestingbotREST(key, secret); ArrayList tunnels = restApi.getTunnels(); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getTunnels(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tunnel.get_tunnels() const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const tunnels = await api.getTunnelList(); Response: [ { "ip":"xx", "private_ip":"xx", "state":"READY", "id":1, "requested_at"=>"2013-04-23 01:34:23" } ] ## TestingBot Tunnel Delete Delete an active [TestingBot Tunnel](https://testingbot.com/support/tunnel) in your account. Usually the tunnel jar will issue this call automatically when you gracefully exit the jar. You can also use this API call, which destroys the tunnel VM. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/tunnel/:id" \ -X DELETE \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.delete_tunnel(tunnel_identifier) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.deleteTunnel(String tunnelId); $api = new TestingBot\TestingBotAPI($key, $secret); $api->deleteTunnel($tunnelID); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.tunnel.delete_tunnel(tunnelId) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); await api.deleteTunnel(tunnelId); Response: { "success":true } ## List Codeless tests Will return a list of all your Codeless Automation tests. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/lab" \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const codelessTests = await api.getCodelessTests(); Arguments: - (int) **offset** (optional) (default 0) - paginate tests starting from this number - (int) **count** (optional) (default 10, max 500) - number of tests to fetch Response: { "data":[ { "id":215, "enabled":false, "alerts":[], "url":"https://testingbot.com/", "name":"testingbot", "created_at":"2012-03-12T20:03:45Z", "updated_at":"2012-03-13T20:26:43Z", "last_run":"2012-03-13T06:50:48Z", "browsers":[ {"name":"firefox","version":10,"os":"LINUX"} ] }], "meta": { "offset":2, "count":3, "total":25 } } ## Specific Codeless test info This call will return info for a specific Codeless test. In the example below, the response will contain info for a test with id 215. $ curl "https://api.testingbot.com/v1/lab/215" \ -u key:secret Arguments: - (int) **id** - a unique identifier identifying your test in the TestLab Response: { "id":215, "enabled":false, "alerts":[], "url":"https://testingbot.com/", "name":"testingbot", "created_at":"2012-03-12T20:03:45Z", "updated_at":"2012-03-13T20:26:43Z", "last_run":"2012-03-13T06:50:48Z", "browsers":[ {"name":"firefox","version":10,"os":"LINUX"} ] } Possible errors: - 404 Not found - codeless test not found ## Create a Codeless Test Create a Codeless Test [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/lab" \ -u key:secret -d "test[name]=test" -d "test[cron]=31 * * * *" const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const testData = { name: 'My Codeless Test', // Required: Test name url: 'https://example.com', // Required: URL to test ai_prompt: 'Test the login flow', // AI test agent prompt cron: '0 0 * * *', // Optional: Cron schedule screenshot: true, // Optional: Take screenshots video: false, // Optional: Record video idletimeout: 60, // Optional: Idle timeout in seconds screenresolution: '1920x1080', // Optional: Screen resolution }; const result = await api.createCodelessTest(testData); Arguments: - (string) **test[name]** - name of the test **\* required argument** - (string) **test[url]** - url to test **\* required argument** - (string) **test[cron]** - cron format, when to run the test - (boolean) **test[screenshot]** - take screenshots - (boolean) **test[video]** - record video - (int) **test[idletimeout]** - how long we keep a test open without receiving a request - (string) **test[screenresolution]** - screenresolution of the OS - (string) **test[ai\_prompt]** - the prompt to tell the [AI test agent](https://testingbot.com/support/ai/codeless) what to test. Indicate in your own language what should be tested. ### Upload .side file You can upload a `.side` file, generated with [Selenium IDE](https://testingbot.com/support/web-automate/codeless-automation/add-test), to the TestingBot REST-API to immediately create a test and upload all steps from the file. $ curl -X POST "https://api.testingbot.com/v1/lab" \ -u key:secret -F "test[name]=test" -F "test[cron]=31 * * * *" -F "file=@/Users/{yourName}/example.side" Arguments: - (string) **test[name]** - name of the test **\* required argument** - (File) **filepath** - to the `.side` file on your machine **\* required argument** - (string) **test[cron]** - cron format, when to run the test Response: [{"success":true, "lab_test_id": 59392}] ## Delete Codeless test This call will delete a specific Codeless test. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/lab/215" \ -X DELETE \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const result = await api.deleteCodelessTest(testId); Arguments: - (string) **id** - a unique identifier identifying your test in the TestLab Response: { "success":true } Possible errors: - 404 Not found - codeless test not found ## Update Codeless test This call will update a specific Codeless test. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/lab/215" \ -X PUT \ -d "test[cron]=* * * * *" \ -u key:secret const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const updateData = { test: { name: 'Updated Test Name', cron: '0 12 * * *' } }; const result = await api.updateCodelessTest(updateData, testId); Arguments: - (string) **id** - a unique identifier identifying your test in the TestLab - (string) **url** - (string) **name** - (string) **cron** - (boolean) **enabled** Response: { "success":true } Possible errors: - 404 Not found - codeless test not found ## Schedule Codeless Test Add or update the Codeless Test Schedule. You can schedule when/at which interval a test should be run. $ curl "https://api.testingbot.com/v1/lab/215/schedule" \ -X POST \ -d "type=once" \ -d "day=2020-03-01" \ -d "hour=00:00" \ -u key:secret Arguments: - (string) **type** once, daily, weekly, custom (cron format) - (string) **day** 2020-03-01 for example (to be used with 'once' or 'weekly') - (string) **hour** 00:01 for example (to be used with 'once', 'daily' or 'weekly') - (string) **cronFormat** \*/5 \* \* \* \* for example ([cron format](https://en.wikipedia.org/wiki/Cron)) Response: { "success":true } Possible errors: - 404 Not found - codeless test not found The callback URL will receive these (post data) parameters: 'success' => success (boolean), 'job_id' => job_id, 'test_ids[]' => [test_ids], 'session_ids[]' => [session_ids] 'errors[]' => json encoded errors ## Codeless Test Alert Add or update the Codeless Test Alert. You can receive an alert via e-mail, Webhook or SMS message. $ curl "https://api.testingbot.com/v1/lab/215/alert" \ -X POST (or PUT for update) \ -d "kind=EMAIL" \ -d "level=IMMEDIATELY" \ -d "content=my@email.com" \ -u key:secret Arguments: - (string) **kind** EMAIL, API or SMS - (string) **level** IMMEDIATELY or DAILY - (string) **content** the email address, telephone number or callback URL Response: { "success":true } Possible errors: - 404 Not found - codeless test not found The callback URL will receive these (post data) parameters: 'success' => success (boolean), 'job_id' => job_id, 'test_ids[]' => test_ids 'errors[]' => json encoded errors ## Codeless Test Report Add or update the Codeless Test Report setting. You can receive a daily report about your test success/fail rate. $ curl "https://api.testingbot.com/v1/lab/215/report" \ -X POST (or PUT for update) \ -d "email=my@email.com" \ -d "cron=*/5 * * * *" \ -u key:secret Arguments: - (string) **email** the email address to contact - (string) **cron** a [cron format](https://en.wikipedia.org/wiki/Cron) Response: { "success":true } Possible errors: - 404 Not found - codeless test not found ## Modify Test Steps Update the steps for this test. Will remove all steps and add the steps you specify. $ curl "https://api.testingbot.com/v1/lab/215/steps" \ -X POST \ -d "steps[][cmd]=open" \ -d "steps[][locator]=/" \ -d "steps[][value]=" \ -d "steps[][order]=0" \ -u key:secret Arguments: - (string) **step[cmd]** - Selenium RC command - (int) **step[order]** - Define where this step should be located in the list of steps - (string) **step[locator]** - Selenium RC locator - (string) **step[value]** - Selenium RC value Response: { "success":true } Possible errors: - 404 Not found - codeless test not found ## List Test Steps This will return all steps for a specific Codeless Test. $ curl -u key:secret "https://api.testingbot.com/v1/lab/215/steps" Arguments: - (int) **offset** (optional) (default 0) - paginate steps starting from this number - (int) **count** (optional) (default 10, max 500) - number of steps to fetch Response: { "data": [{ "test_order": 0, "cmd": "open", "locator": "/", "value": "", "created_at": "2019-05-02T14:33:48.000Z", "updated_at": "2019-05-02T14:33:48.000Z" }, { "test_order": 1, "cmd": "type", "locator": "id=username", "value": "test", "created_at": "2019-05-02T14:33:48.000Z", "updated_at": "2019-05-02T14:33:48.000Z" }, { "test_order": 2, "cmd": "type", "locator": "id=password", "value": "test", "created_at": "2019-05-02T14:33:48.000Z", "updated_at": "2019-05-02T14:33:48.000Z" } ], "meta": { "offset": 0, "count": 3, "total": 3 } } Possible errors: - 404 Not found - codeless test not found ## Get Browsers for Test Retrieve what browsers this Codeless Test will run on. $ curl "https://api.testingbot.com/v1/lab/:suiteId/browsers" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite Response: [{"name":"firefox","version":"41","os":"VISTA"}] ## Update Browsers for Test Update a Codeless Test, indicate on which browsers the test should run. This call will override all existing browsers attached to this test. $ curl -X POST "https://api.testingbot.com/v1/lab/:suiteId/browsers" \ -u key:secret -d "browser_ids=515,518 Arguments: - (int) **suiteId** - unique Id for this suite - (string) **browser\_ids** - (comma-separated list) - list of all browser\_ids to add to this test You can get the browser\_ids by using the **List of browsers** call and use the browser\_ids in that response. Response: {"success":true} ## Run a specific Codeless test This call will run a specific Codeless test on our grid. Upload a Selenium test in our TestLab, indicate on which browsers you want it to run and then run the test with this API call. You could use this call to run tests when you wish, for example before/after deployment of your code. Since this call is asynchronously (test takes too long to be processed during the API call), you need to specify an API callback page in the alert section of your Codeless test. This call will return a success state and a job\_id, which you can use to [query the progress](https://testingbot.com#testjob) of the test. $ curl "https://api.testingbot.com/v1/lab/215/trigger" \ -X POST \ -d "" \ -u key:secret Arguments: - (int) **testid** - a unique number identifying your test in the TestLab - (string) **url** (optional) - change the baseURL for this test Response: { "success":true, "job_id" : 14 } Possible errors: - 404 Not found - codeless test not found ## Stop a specific Codeless test This call will stop a specific Codeless test currently running on our grid. As soon as we receive this call, we will no longer continue running the remaining steps in the running Codeless test. $ curl "https://api.testingbot.com/v1/lab/:testid/stop" \ -X PUT \ -u key:secret Arguments: - (int) **testid** - a unique number identifying your test in the TestLab - (int) **browser\_id** (optional) - a browser\_id to only stop the test for this browser Response: { "success":true } Possible errors: - 404 Not found - codeless test not found ## Run all Codeless tests This call will run all Codeless tests on our grid. This call will return a success state and a job\_id, which you can use to [query the progress](https://testingbot.com#testjob) of the tests. $ curl "https://api.testingbot.com/v1/lab/trigger_all" \ -X POST \ -d "" \ -u key:secret Arguments: - (string) **url** (optional) - change the baseURL for this test Response: { "success":true, "job_id" : 14 } ## Test Job This call will return the status of a running test or suite, initiated by an API call. $ curl "https://api.testingbot.com/v1/jobs/:jobId" \ -u key:secret Arguments: - (int) **:jobId** - a unique number identifying your job Response: { "status":"FINISHED", "created_at":"2016-04-15T13:47:39.000Z", "updated_at":"2016-04-15T13:49:30.000Z", "success":false, "test_ids":[ 6620446 ], "errors":[ { "msg":"Actual value 'Google' did not match 'Goooogle'", "step":"verifyTitle", "browser":{ "name":"firefox", "version":"43", "os":"VISTA" }, "time":"2016-04-15T13:48:25.839Z", "test":6620446 } ] } The various states are: `WAITING`, `RUNNING` and `FINISHED`. Possible errors: - 404 Not found - job not found ## Webhook If you initiated an API call running one or all tests, you will want to know the results of the test(s). We post the result of the test(s) back to the location you specified in our TestLab (alerts section). Sample post data: { "success":"false", "errors":[ { "msg" : "word Not found", "step" : "verifyTextPresent", "browser" : { "name" : "iexplore", "version" : "8", "os" : "WINDOWS" }, "time" : "2012-03-13 20:34:59 UTC", "test_id" : "48586", "job_id": 17, "lab_id" : 133 } ], "job_id":3, "test_ids":[48586] } { "success":"true", "test_ids":[48586, 48587], "job_id":3 } ## List Codeless Suites Get a list of all Lab Suites currently available for your account in the TestLab. $ curl "https://api.testingbot.com/v1/labsuites?offset=0&count=10" \ -u key:secret Arguments: - (int) **offset** (optional) (default 0) - paginate suites starting from this number - (int) **count** (optional) (default 10, max 500) - number of suites to fetch Response: { "data": [ { "id": 1051, "enabled": true, "alerts": [ { "type": "API", "value": "https:\/\/mysite.com\/callback\/", "level": "IMMEDIATELY" } ], "name": "Example", "created_at": "2017-03-07T19:11:41.000Z", "updated_at": "2017-03-09T12:17:22.000Z", "last_run": "2017-03-09T12:17:22.000Z", "cron": null, "browsers": [ { "name": "firefox", "version": "41", "os": "VISTA" } ], "test_count": 5 } ], "meta": { "offset": 0, "count": 10, "total": 1 } } ## Get Codeless Suite Details Get information about a specific Codeless Suite. $ curl "https://api.testingbot.com/v1/labsuites/:suiteId" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite Response: { "enabled": true, "alerts": [ { "type": "API", "value": "https:\/\/mysite.com\/callback\/", "level": "IMMEDIATELY" } ], "name": "Example", "created_at": "2017-03-07T19:11:41.000Z", "updated_at": "2017-03-09T12:17:22.000Z", "last_run": "2017-03-09T12:17:22.000Z", "cron": null, "test_count": 5 } ## Run a specific Codeless suite This call will run a specific TestLab suite on our grid. Upload a Selenium suite in our TestLab, indicate on which browsers you want it to run and then run the suite with this API call. You could use this call to run suites when you wish, for example before/after deployment of your code. Since this call is asynchronously (suite takes too long to be processed during the API call), you need to specify an API callback page in the alert section of your TestLab suite. This call will return a success state and a job\_id, which you can use to [query the progress](https://testingbot.com#testjob) of the test. $ curl "https://api.testingbot.com/v1/labsuites/:suiteId/trigger" \ -X POST \ -d "" \ -u key:secret Arguments: - (int) **:suiteId** - a unique number identifying your suite in the TestLab Response: { "success":true, "job_id" : 14 } Possible errors: - 404 Not found - codeless test not found ## Create a Codeless Suite Create a Codeless test suite. $ curl -X POST "https://api.testingbot.com/v1/labsuites" \ -u key:secret -d "suite[name]=test" -d "suite[cron]=31 * * * *" Arguments: - (string) **suite[name]** - name of the suite. - (string) **suite[cron]** - cron format, when to run the suite. - (boolean) **suite[screenshot]** - take screenshots for every step. - (boolean) **suite[video]** - record video of this test. - (int) **suite[idletimeout]** - how long before we consider a test to be idle. - (string) **suite[screenresolution]** - screenresolution of the OS. Response: [{"success":true, "suite_id": 59391}] ## Delete a Codeless Suite Delete a Codeless suite. $ curl -X DELETE "https://api.testingbot.com/v1/labsuites/:suiteId" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite Response: {"success":true} ## Get Browsers for Codeless Suite Retrieve what browsers this Codeless Suite will run on. $ curl "https://api.testingbot.com/v1/labsuites/:suiteId/browsers" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite Response: [{"name":"firefox","version":"41","os":"VISTA"}] ## Update Browsers for Codeless Suite Update a Codeless Suite, indicate on which browsers the suite should run. This call will override all existing browsers attached to this suite. $ curl -X POST "https://api.testingbot.com/v1/labsuites/suiteId/browsers" \ -u key:secret -d "browser_ids=515,518 Arguments: - (int) **suiteId** - unique Id for this suite - (string, comma-separated list) **browser\_ids** - list of all browser\_ids to add to this suite You can get the browser\_ids by using the [List of browsers](https://testingbot.com#browsers) call and use the browser\_ids in that response. Response: {"success":true} ## Get Tests for a Codeless Suite Retrieves all tests in this Suite. $ curl "https://api.testingbot.com/v1/labsuites/:suiteId/tests" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite - (int) **offset** (optional) (default 0) - paginate tests starting from this number - (int) **count** (optional) (default 10, max 500) - number of tests to fetch Response: { "data": [ { "id": 18666, "enabled": true, "alerts": [], "url": "https:\/\/mysite.com\/", "name": "MyTest", "created_at": "2017-03-09T12:14:48.000Z", "updated_at": "2017-03-09T12:19:30.000Z", "last_run": "2017-03-09T12:19:30.000Z", "cron": null, "browsers": [ { "name": "firefox", "version": "41", "os": "VISTA" } ] } ], "meta": { "offset": 0, "count": 1, "total": 1 } } ## Add Tests to a Codeless Suite Add one or more tests to this suite. $ curl -X POST "https://api.testingbot.com/v1/labsuites/:suiteId/tests" \ -u key:secret -d "test_ids=3,4" Arguments: - (int) **suiteId** - unique Id for this suite - (string, comma-separated) **test\_ids** - comma-separated list of test\_ids to add to this suite. Response: {"success": true} Possible errors: - 404 Not found - suite not found - 400 Bad request - missing test\_ids parameter ## Remove Tests from a Codeless Suite Remove a test from a Test Suite. $ curl -X DELETE "https://api.testingbot.com/v1/labsuites/:suiteId/tests/:testId" \ -u key:secret Arguments: - (int) **suiteId** - unique Id for this suite - (int) **testsId** - unique Id for the test in the suite Response: {"success": true} Possible errors: - 404 Not found - suite not found ## TestingBot Storage - Upload File TestingBot Storage makes it easy to upload a file you want to include during your test(s). You can use this functionality to test your Android (.apk/.aab) or iOS app (.zip/.ipa), or to [download and run before a test starts](https://testingbot.com/support/web-automate/selenium/test-options#prerun). Files uploaded to TestingBot Storage are automatically pruned after 62 days. You can also delete the file manually be using the Delete API call. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -F "file=@/path/to/app/file/Application-debug.apk" require 'testingbot' api = TestingBot::Api.new(key, secret) api.upload_local_file(localFilePath) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotStorageUploadResponse uploadResponse = restApi.uploadToStorage(File file); $api = new TestingBot\TestingBotAPI($key, $secret); $api->uploadLocalFileToStorage($pathToLocalFile); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.upload_local_file(localFilePath) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); api.uploadFile(localFilePath, function(error, response) { // response.app_url }); Response: {"app_url": "tb://398eijf83i"} The `app_url` will be a random string. If you'd like to use your own name, for example because you don't want to keep updating your test scripts each time you add a new app version, then please see below: **Specify your own app name:** $ curl -X POST "https://api.testingbot.com/v1/storage/your_name" \ -u key:secret -F "file=@/path/to/app/file/Application-debug.apk" Response: {"app_url": "tb://your_name"} Instead of uploading a file from your computer to TestingBot storage, you can also pass an URL where we should download your app: [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -d "url=https://...." require 'testingbot' api = TestingBot::Api.new(key, secret) api.upload_remote_file(remoteFileUrl) TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotStorageUploadResponse uploadResponse = restApi.uploadToStorage(String fileUrl); $api = new TestingBot\TestingBotAPI($key, $secret); $api->uploadRemoteFileToStorage($urlToRemoteFile); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.upload_remote_file(localFilePath) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); api.uploadFile(remoteFileUrl, function(error, response) { // response.app_url }); Uploads to our TestingBot Storage are automatically deleted after 62 days. We've got an example on how to upload a file with Java at our [App Automate Java GitHub Repository](https://github.com/testingbot/app-automate-java). ## TestingBot Storage - Update File If you want to update a file you already uploaded, please use this API call. Use the `app_url` you received from the original file upload, without the `tb://` scheme. [cURL](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/storage/{app_url}" \ -u key:secret -F "file=@/path/to/app/file/Application-debug.apk" const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const appUrl = await api.uploadFile(localFilePath); Response: {"app_url": "tb://398eijf83i"} In the example above, if your `app_url` was `tb://my-file` you would use the URL `https://api.testingbot.com/v1/storage/my-file` ## TestingBot Storage - Uploaded File Data Retrieve various meta data from a previously uploaded file. Use the `app_url` you received from the original file upload. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/storage/:app_url" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_uploaded_file(app_url) TestingbotREST restApi = new TestingbotREST(key, secret); TestingBotStorageFile storedFile = restApi.getStorageFile(String appUrl); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getStorageFile($appUrl); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.get_stored_file(app_url) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); await api.getStorageFile(appUrl); Response: { "app_url":"tb://0ec522702cd81ec1374e9b3c", "url":"http://...", "id":261, "type":"ANDROID", "filename":"sample.apk", "version":"1.0.1", "min_device_version": "12.0", "thumb":"https://...image.png", "created_at":"2019-03-08T08:58:32.000Z" } ## TestingBot Storage - Upload Files List This API call will return a list of files you or your team members have previously uploaded. The Response will contain a `url` parameter which is a signed URL you can use for up to 4 hours. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/storage/" require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_uploaded_files(offset = 0, count = 30) TestingbotREST restApi = new TestingbotREST(key, secret); TestingBotStorageFileCollection fileList = restApi.getStorageFiles(int offset, int count); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getStorageFiles(); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.get_stored_files(offset=0, limit=30) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const files = await api.getStorageFiles(offset, count); Response: [{ "app_url":"tb://....", "url":".....", "id":44, "type":"ANDROID", "filename":"sample.apk", "version":"1.0.1", "min_device_version": "23", "thumb":"https://...image.png", "created_at":"2019-01-08T13:42:42.000Z" }] ## TestingBot Storage - Delete a file from Storage Delete a file previously uploaded to TestingBot Storage. Use the `app_url` parameter of the file you wish to delete, for example from `tb://398eijf83i`. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X DELETE "https://api.testingbot.com/v1/storage/398eijf83i" require 'testingbot' api = TestingBot::Api.new(key, secret) api.delete_uploaded_file(file_identifier) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.deleteStorageFile(String appUrl); $api = new TestingBot\TestingBotAPI($key, $secret); $api->deleteStorageFile($appUrl); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.remove_file(appUrl) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const success = await api.deleteStorageFile(fileId); Response: {"success": true} ## IP Ranges for whitelisting If you would like to whitelist the IPs that are used by the TestingBot machines, you can use the API call below to fetch an up-to-date list. [cURL](https://testingbot.com#) $ curl "https://api.testingbot.com/v1/configuration/ip-ranges" Response: ["109.68.162.161","109.68.162.165","78.20.187.211","162.55.135.22","95.217.83.184","95.216.39.110","65.21.76.124","95.216.229.109","142.132.137.7"] ## Share Test Result You can easily share a single test result with someone in a safe way, without the other person needing an account. To share a test result, you'll need to create the following url: https://testingbot.com/tests/ **sessionId**?auth= **authentication-hash** The sessionId is the ID assigned by the Selenium grid to identify a single test. You can find this sessionId in your logs when running a test. The authentication hash is created with md5 in the following format: Digest::MD5.hexdigest("#{client_key}:#{client_secret}#{session_id}") [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) require 'testingbot' api = TestingBot::Api.new(key, secret) api.get_authentication_hash(identifier) TestingbotREST restApi = new TestingbotREST(key, secret); String hash = restApi.getAuthenticationHash(String identifier); $api = new TestingBot\TestingBotAPI($key, $secret); $api->getAuthenticationHash($identifier); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.get_share_link(identifier) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const hash = api.getAuthenticationHashForSharing(identifier); An example link would then be: https://testingbot.com/tests/9jf392fj3j2f3ojid8?auth=230i439uf3fojf ## Share Test Build With TestingBot, it is possible to group several tests under one build identifier. In our member area, you can then see all the tests grouped by builds. To link directly to a build overview, please see this example: https://testingbot.com/builds/ **build-identifier**?auth= **authentication-hash** &key= **key** To generate the authentication-hash, you must concatenate key, secret and build\_identifier and take the MD5 hash: Digest::MD5.hexdigest("#{client_key}:#{client_secret}#{build-identifier}") The build-identifier is the custom string you can [send as an option](https://testingbot.com/support/web-automate/selenium/test-options#build) to group several tests. --- URL: https://testingbot.com/support/k6-browser-testing # k6 Browser Testing k6 is an open-source tool designed to do easy load testing against websites. With the [k6 browser module](https://grafana.com/docs/k6/latest/using-k6-browser/), you can connect to a CDP-compatible browser grid such as TestingBot. Simply configure your k6 test to use the TestingBot grid, and instantly get access to a high capacity cloud of browsers. With this integration, you can run tests in parallel, targeting different browsers, versions and operating systems. Each test comes with logs, screenshots and a video. ## Setup To get started, please make sure you [install k6](https://k6.io/docs/get-started/installation/). ### macOS brew install k6 ### Windows winget install k6 --source winget ### Linux sudo gpg -k sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69 echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list sudo apt-get update sudo apt-get install k6 ## Example Next, let's run a sample browser test using k6 on the TestingBot browser grid. Please see the example below. To connect to the TestingBot CDP grid, you will need to specify a `K6_BROWSER_WS_URL` environment variable. This needs to contain the URL to the TestingBot grid, together with the credentials and (url-encoded) capabilities. K6_BROWSER_WS_URL="wss://cloud.testingbot.com/?key=...&secret=...&capabilities=%7B%22browserName%22%3A%22chrome%22%2C%22browserVersion%22%3A%22latest%22%7D" To run the example below, you can use the following command in your terminal: K6_BROWSER_WS_URL="wss://cloud.testingbot.com/?key=...&secret=...&capabilities=%7B%22browserName%22%3A%22chrome%22%2C%22browserVersion%22%3A%22latest%22%7D" K6_BROWSER_ENABLED=true k6 run k6_sample.js **k6\_sample.js** import { browser } from 'k6/browser'; import { check } from 'k6'; export const options = { scenarios: { ui: { executor: 'shared-iterations', options: { browser: { type: 'chromium', }, }, }, }, thresholds: { checks: ['rate==1.0'], }, }; export default async function () { const context = await browser.newContext(); const page = await context.newPage(); try { await page.goto('https://test.k6.io/my_messages.php'); await page.locator('input[name="login"]').type('admin'); await page.locator('input[name="password"]').type('123'); const submitButton = page.locator('input[type="submit"]'); await Promise.all([page.waitForNavigation(), submitButton.click()]); const header = await page.locator('h2').textContent(); check(page, { header: header == 'Welcome, admin!', }); } finally { await page.close(); } } ### K6\_BROWSER\_WS\_URL To construct the `K6_BROWSER_WS_URL`, you'll need to urlencode the capabilities: const capabilities = { browserName: 'chrome', browserVersion: 'latest', platform: 'VENTURA' } const url = `wss://cloud.testingbot.com/?key=...&secret=...&capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` ## Test Results You can find the results of your k6 browser test in your terminal. The TestingBot member area will contain a list of all k6 tests, together with logs, screenshots and a video of each test. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate # App Automation with TestingBot TestingBot provides remote devices for testing your native mobile applications. You can run automated tests on real devices, including iPhone and Android devices, as well as Smart TV OTT devices. We support various testing frameworks such as Appium, Espresso, XCUITest, Maestro and more. ![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg) ### [Appium](https://testingbot.com/support/app-automate/appium) Appium is a popular test-framework, designed to automate mobile app testing. - [C#](https://testingbot.com/support/app-automate/appium/csharp) - [Java](https://testingbot.com/support/app-automate/appium/java) - [NodeJS](https://testingbot.com/support/app-automate/appium/nodejs) - [Python](https://testingbot.com/support/app-automate/appium/python) - [Flutter](https://testingbot.com/support/app-automate/appium/flutter) - [Ruby](https://testingbot.com/support/app-automate/appium/ruby) - [PHP](https://testingbot.com/support/app-automate/appium/php) ![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg) ### [Espresso](https://testingbot.com/support/app-automate/espresso) Espresso is a testing framework for Android to automate UI testing. - [Espresso Documentation](https://testingbot.com/support/app-automate/espresso) ![XCUITest Testing](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg) ### [XCUITest](https://testingbot.com/support/app-automate/xcuitest) XCUITest is a testing framework for iOS to automate UI testing. - [XCUITest Documentation](https://testingbot.com/support/app-automate/xcuitest) ![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg) ### [Maestro](https://testingbot.com/support/app-automate/maestro) Maestro is a testing framework for mobile applications to automate UI testing. - [Maestro Documentation](https://testingbot.com/support/app-automate/maestro) ![Electron Testing](https://testingbot.com/assets/environments/svg/electron-91b2641c5cea963ea9c261f274ae480fc4fbc689889a058158c9ebbcd559b622.svg) ### [Electron](https://testingbot.com/support/app-automate/electron) Electron is a framework for building cross-platform desktop applications with web technologies. - [Electron Documentation](https://testingbot.com/support/app-automate/electron) ### [Smart TV Testing](https://testingbot.com/support/app-automate/smart-tv) Test Smart-TV applications with TestingBot. - [Smart TV Documentation](https://testingbot.com/support/app-automate/smart-tv) --- URL: https://testingbot.com/support/app-automate/devices - [Desktop Browsers & Emulators](https://testingbot.com/support/web-automate/browsers) - [Physical Mobile Devices](https://testingbot.com#) # Physical Mobile Devices These are the DesiredCapabilities necessary to run an Automated Test: #### Platform - All Platforms - Apple iOS - Android #### Android Version - All Versions - Android 16.0 - Android 15.0 - Android 14.0 - Android 13.0 - Android 12.0 - Android 11.0 - Android 10.0 - Android 9.0 - Android 7.1 - Android 6.0 #### iOS Version - All Versions - iOS 26.2 - iOS 26.0 - iOS 18.5 - iOS 18.2 - iOS 18.0 - iOS 17.6 - iOS 17.5 - iOS 16.5 - iOS 16.3 - iOS 15.0 - iOS 14.8 - iOS 14.7 - iOS 14.5 - iOS 14.0 - iOS 13.5 - iOS 13.4 - iOS 12.2 - iOS 12.1 #### Resolution - All Resolutions - 1440x3440 - 1440x3200 - 1260x2736 - 1179x2556 - 1170x2532 - 1080x2424 - 1080x2400 - 1080x2340 - 1080x2220 - 1200x1920 - 1080x1920 - 828x1792 - 720x1600 - 750x1334 - 810x1080 - 768x1024 - 758x1011 - ![Test online on Galaxy S8](https://testingbot.com/assets/devices/160h/1-1f8a8f10826bfb4e6109e741abfaa6de5cc97901aa7626b6e396e65d14b93cc8.png) Galaxy S8 Resolution: 1080x2220 CPU: Octa-core (4x2.3 GHz Mongoose M2 & 4x1.7 GHz Cortex-A53) Model: SM-G950U1 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "9.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S8"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 6s](https://testingbot.com/assets/devices/160h/2-67e8216b79cb1c4fc2d07b796042245e830042550a7adf3ebb1d8287da9715ad.png) iPhone 6s Resolution: 750x1334 CPU: Apple A9 Model: MKQN2ZD/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "12.1"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 6s"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPad (6th generation)](https://testingbot.com/assets/devices/160h/3-db10ee5ecdf299dd3932e8938c802d0e57265406a5f3bc522841b72b84cb0d96.png) iPad (6th generation) Resolution: 768x1024 CPU: Apple A10 Model: MR7G2NF/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "13.5"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPad (6th generation)"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPhone XR](https://testingbot.com/assets/devices/160h/5-7ca9c0a7d4fe6708a2c08d25bd23663169243c9f90807be323ab428590491cf9.png) iPhone XR Resolution: 828x1792 CPU: Apple A12 Bionic Model: MRY42B/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "16.3"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone XR"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Pixel](https://testingbot.com/assets/devices/160h/7-23de2fe6c4a4119d402d125ee669fa908692350c7da36139b4702f5b184cfe3d.png) Pixel Resolution: 1080x1920 CPU: ARM - Quad-core - 1593Mhz Model: PQ1A.190105.004 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "7.1"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Pixel"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Galaxy S10](https://testingbot.com/assets/devices/160h/8-c140ac807c625801f548a906e01355158b71c361fdc86ddd9a645ad935827c05.png) Galaxy S10 Resolution: 1440x3440 CPU: Octa-core Model: SM-G973F [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "10.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S10"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Galaxy Tab A](https://testingbot.com/assets/devices/160h/9-1db1e22ab4516862797cca7693079084ea3e3582f911d7b51971754d83974752.png) Galaxy Tab A Resolution: 1200x1920 CPU: ARM - Quad-core - 1200Mhz Model: SM-T510 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "9.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy Tab A"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 8](https://testingbot.com/assets/devices/160h/10-5d4c0cdcd2238d10c36916a95e87e7541d4ace0a45436637f51f494cf4308ede.png) iPhone 8 Resolution: 750x1334 CPU: ARM - Dual-core - 1840Mhz Model: MQ6H2 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "13.4"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 8"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPhone 11](https://testingbot.com/assets/devices/160h/11-3ddb6dcb39e2d4e307eba6b52ba4bad5839054feb89abcd74cae48235edab46d.png) iPhone 11 Resolution: 828x1792 CPU: Model: MWLT2 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 11"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Galaxy S20](https://testingbot.com/assets/devices/160h/12-3d5eea05f5802ad49748405da14a5531d07a24e3b5a9fe52c8ca2b29c63a6774.png) Galaxy S20 Resolution: 1440x3200 CPU: ARM - Quad-core - 1593Mhz Model: E [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "10.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S20"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 12](https://testingbot.com/assets/devices/160h/14-feb85685f170057dbc2d7c6295001ac6d8bc52d0c0e0ba03053d779f4f73ad9c.png) iPhone 12 Resolution: 1170x2532 CPU: Apple A14 Bionic Model: MWLT2 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.5"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 12"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Galaxy S21](https://testingbot.com/assets/devices/160h/15-540f427f967d455d2b8b95b70aada460fce369c428998422462dfd56d56013f6.png) Galaxy S21 Resolution: 1080x2400 CPU: ARM - Quad-core - 1593Mhz Model: E [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "11.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S21"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Mi 10](https://testingbot.com/assets/devices/160h/16-7627417896e3822627bc0d60fc33c605b7db401a8c58527834407506faf43fab.png) Mi 10 Resolution: 1080x2400 CPU: ARM - Single-core - 1690Mhz Model: M2007J3SY [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "12.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Mi 10"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Galaxy A12](https://testingbot.com/assets/devices/160h/17-a6829514cbda5863012c38310b62729e9c30f4e594ef084bc5b374cd18d53fe0.png) Galaxy A12 Resolution: 720x1600 CPU: Model: SM-A125F [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "11.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy A12"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPad (8th generation)](https://testingbot.com/assets/devices/160h/18-efdf40f2da9a603ff90fb75e8cc846ac7e406c625a2bb4322680e71fea50a8de.png) iPad (8th generation) Resolution: 758x1011 CPU: ARM - Quad-core - 2340MHz Model: MR7G2NF/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "15.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPad (8th generation)"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPhone XR](https://testingbot.com/assets/devices/160h/19-7ca9c0a7d4fe6708a2c08d25bd23663169243c9f90807be323ab428590491cf9.png) iPhone XR Resolution: 828x1792 CPU: ARM - Single-core - 2390Mhz Model: MRY42B/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.8"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone XR"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on OnePlus 9](https://testingbot.com/assets/devices/160h/20-9861fccb89ed97d0fdcd807c7178404c01362dff69701adca37023605d27f1b7.png) OnePlus 9 Resolution: 1080x2400 CPU: ARM - Quad-core - 1593Mhz Model: CPH2251 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "11.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "OnePlus 9"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Pixel 6](https://testingbot.com/assets/devices/160h/21-9a6205155ee4ed02bc22b008f81653b9f60dce9641bdd34ad017b7cf73fd2fe1.png) Pixel 6 Resolution: 1080x2400 CPU: ARM - Quad-core - 1593Mhz Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "13.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Pixel 6"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 13](https://testingbot.com/assets/devices/160h/22-69483440c27820ca3dbcc051d3823215e595f61aa21b768460791389612bf12b.png) iPhone 13 Resolution: 1170x2532 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "18.5"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 13"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Galaxy S23](https://testingbot.com/assets/devices/160h/23-c2df9301b8ca06b86395ca220b717010b21a0a0fc552b1e3be83112ac18b0988.png) Galaxy S23 Resolution: 1080x2340 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "13.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S23"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 14](https://testingbot.com/assets/devices/160h/24-334a9172a1cd4d0ebcdafd77a15bae6eedcbccffd8470ac5735f50570ba74620.png) iPhone 14 Resolution: 1170x2532 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "17.6"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 14"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPhone 11](https://testingbot.com/assets/devices/160h/25-3ddb6dcb39e2d4e307eba6b52ba4bad5839054feb89abcd74cae48235edab46d.png) iPhone 11 Resolution: 828x1792 CPU: Model: MWLT2 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.8"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 11"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPad (8th generation)](https://testingbot.com/assets/devices/160h/26-3dfdc59679360eafc8969822e41f13f9fca3020e011ec31e38e7eed0617fd042.png) iPad (8th generation) Resolution: 810x1080 CPU: ARM - Quad-core - 2340MHz Model: MR7G2NF/A [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.7"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPad (8th generation)"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on iPhone 15](https://testingbot.com/assets/devices/160h/27-fa43101c0c582cc4892313c96ddcdf88ccae7c4ffff425cd20989099345ea1d0.png) iPhone 15 Resolution: 1179x2556 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "18.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 15"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Pixel 8](https://testingbot.com/assets/devices/160h/28-98ab89fcf1461b958032b26327abb47a842592cbc341b0522de3c1b21901763c.png) Pixel 8 Resolution: 1080x2400 CPU: Google Tensor G3 (4 nm) Model: GKWS6 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Pixel 8"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Galaxy S24](https://testingbot.com/assets/devices/160h/29-721713244928fc0799e7e9d60e3e260e811243489e2d572d6009fb7c8ed9019d.png) Galaxy S24 Resolution: 1080x2340 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S24"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Galaxy A55](https://testingbot.com/assets/devices/160h/30-4e523289f8fe0edae798e39d71f3c0cf7930cbdc4807771da84e201ec7dd77f0.png) Galaxy A55 Resolution: 1080x2340 CPU: Exynos 1480 Model: SM-A556ELBHINS [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy A55"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone SE 2022](https://testingbot.com/assets/devices/160h/31-90fa36ca0531263e241615775883dab78816e6c91e74d66e7603e5b8b7a16928.png) iPhone SE 2022 Resolution: 750x1334 CPU: A15 Bionic Chip Model: A2783 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "17.5"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone SE 2022"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Redmi Note 13](https://testingbot.com/assets/devices/160h/32-2a98c9f3e70285cd2c639462e106b739d893a41ed98e63994e4c24c327ab5e77.png) Redmi Note 13 Resolution: 1080x2400 CPU: Octa-core (2x2.4 GHz Cortex-A76) Model: 23124RA7EO [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "14.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Redmi Note 13"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 16](https://testingbot.com/assets/devices/160h/33-3fe3f72dccbdf4320c88d81c18a9ae9c28dcbd1023e85b71db659ddd1c41752e.png) iPhone 16 Resolution: 1179x2556 CPU: Apple A18 Model: A3287 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "18.2"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 16"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Galaxy S25](https://testingbot.com/assets/devices/160h/34-66fda97a65984960824cbfcb57ad4458c0e9a5d7904982bcb5506776013338c5.png) Galaxy S25 Resolution: 1080x2340 CPU: ARM Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "15.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Galaxy S25"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on Pixel 9](https://testingbot.com/assets/devices/160h/35-3fa3958dd941e15ecfde215bd9d4014952803aef46a16245e04187e824ec59ce.png) Pixel 9 Resolution: 1080x2424 CPU: Google Tensor G4 Model: GUR25 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "16.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Pixel 9"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone 17](https://testingbot.com/assets/devices/160h/36-9527070deeb6aceeb90648e8df41f90d7443eb08b7b41625451dc2f861af845f.png) iPhone 17 Resolution: 1179x2556 CPU: Apple A19 Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "26.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone 17"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Pixel 10](https://testingbot.com/assets/devices/160h/37-d53c19554e3e5731d4238e1c72be755b39eeafafc391bd0da2e92fc97659ee59.png) Pixel 10 Resolution: 1080x2424 CPU: Google Tensor G5 Model: GUR25 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "16.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Pixel 10"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); - ![Test online on iPhone Air](https://testingbot.com/assets/devices/160h/38-d22d9cb8c40d79cfe188f9ab5691b4ef5db63551cd2ae71ba5ecc5cfd59e5398.png) iPhone Air Resolution: 1260x2736 CPU: Apple A19 Pro Model: [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "26.2"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "iPhone Air"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "iOS"); - ![Test online on Huawei P40](https://testingbot.com/assets/devices/160h/39-05227623a4f02381c190b5e7af808c32db0708e365cc6184f1c86f0008cf12e6.png) Huawei P40 Resolution: 1080x2340 CPU: Cortex-A76 Model: ANA-AN00 [Desired Capabilities](https://testingbot.com#) DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "12.0"); caps.setCapability("app", "..URL to your app (apk or ipa).."); caps.setCapability("deviceName", "Huawei P40"); caps.setCapability("realDevice", true); caps.setCapability("platformName", "Android"); --- URL: https://testingbot.com/support/app-automate/electron # Electron Testing [Electron](https://electronjs.org/) is a framework that allows you to create cross-platform native applications by using Javascript code. Electron will embed a Chromium engine in a native app format, allowing web developers to create desktop applications by writing HTML and Javascript code. TestingBot supports running automated WebDriver tests against Electron-based apps on these platforms: - Windows 11 - Windows 10 - macOS Tahoe - macOS Sequoia - macOS Sonoma - macOS Ventura - macOS Monterey All Electron versions from version 16 to the most recent version are supported. TestingBot has created a [demo Electron app](https://github.com/testingbot/testingbot-electron-demo-app), which acts as a simple calculator, to showcase automated Electron app testing. ## Run your first Electron test ### App management To test an Electron app, you'll first need to upload a zip file of your Electron application to a URL where TestingBot can download it from. You can choose to upload this yourself, for example to AWS S3 or use [TestingBot Storage](https://testingbot.com/support/api#upload) to upload your `.zip` file. Note that files uploaded to TestingBot Storage are automatically pruned after 62 days. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -F "file=@/path/to/app/file/electron-app.zip" require 'testingbot' api = TestingBot::Api.new(key, secret) api.upload_local_file('electron-app.zip') TestingbotREST restApi = new TestingbotREST(key, secret); TestingbotStorageUploadResponse uploadResponse = restApi.uploadToStorage(File file); $api = new TestingBot\TestingBotAPI($key, $secret); $api->uploadLocalFileToStorage($pathToLocalFile); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) tb.storage.upload_local_file(localFilePath) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); api.uploadFile(localFilePath, function(error, response) { // response.app_url }); TestingBot Storage will return a `app_url` which you can use in the `tb:app` capability of your test. This is how the capabilities in your test should currently look like: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { "browserName" => "electron", "browserVersion" => "33", "tb:app" => "tb://the-app-url-you-received" # or https://s3.amazonaws.com/... } ChromeOptions options = new ChromeOptions(); options.setCapability("browserName", "electron"); options.setCapability("browserVersion", "33"); options.setCapability("tb:app", "tb://the-app-url-you-received"); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); options.setCapability("tb:options", tbOptions); capabilities = { "browserName": "electron", "browserVersion": "33", "tb:app": "tb://the-app-url-you-received", "tb:options": { "name": "Electron Sample" } } driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", options=webdriver.ChromeOptions().to_capabilities() | capabilities) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'electron', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" }, 'tb:app': 'tb://the-app-url-you-received' // or https://s3.amazonaws.com/... }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions(); chromeOptions.BrowserVersion = "33"; chromeOptions.PlatformName = "Windows 10"; chromeOptions.AddAdditionalChromeOption("browserName", "electron"); var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name }; chromeOptions.AddAdditionalChromeOption("tb:options", tbOptions); chromeOptions.AddAdditionalChromeOption("tb:app", "tb://the-app-url-you-received"); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions, TimeSpan.FromSeconds(600)); ### Binary location Next to the required `app` capability, you will also need to specify a `tb:binary_location` capability. This is the path to the actual Electron app, so that TestingBot knows which file in the `zip` file is the Electron app. For example, if your uploaded zip file is structured like this: TestingBot-Electron-App.zip [testingbot-electron-demo-app.app] [Contents] [MacOS] -- testingbot-electron-demo-app The `binary_location` capability in this case would be: tb:binary_location = "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app" Now the capabilities in your test should look like the example below. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'selenium-webdriver' options = Selenium::WebDriver::Options.chrome options.browser_name = "electron" options.platform_name = "VENTURA" options.browser_version = "31" options.add_option("tb:binary_location", "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app") options.add_option("tb:app", "https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip") http_client = Selenium::WebDriver::Remote::Http::Default.new http_client.open_timeout = 200 http_client.read_timeout = 200 driver = Selenium::WebDriver.for( :remote, url: "https://key:secret@hub.testingbot.com/wd/hub", options: options, http_client: http_client) # Generate two random numbers between 0 and 9 num1 = rand(0..9) num2 = rand(0..9) # Find elements on the page first_number = driver.find_element(id: "btn-#{num1}") second_number = driver.find_element(id: "btn-#{num2}") plus = driver.find_element(id: 'btn-plus') equal = driver.find_element(id: 'btn-equal') # Perform operations first_number.click plus.click second_number.click equal.click # Get the result result_element = driver.find_element(id: 'calc-display') result_text = result_element.text driver.quit raise "Test failed" unless (num1 + num2) == result_text.to_i import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.Random; public class SeleniumTest { public static void main(String[] args) { try { ChromeOptions options = new ChromeOptions(); options.setCapability("browserName", "electron"); options.setCapability("platformName", "VENTURA"); options.setCapability("browserVersion", "31"); options.setCapability("tb:binary_location", "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app"); options.setCapability("tb:app", "https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip"); WebDriver driver = new RemoteWebDriver( new URL("https://key:secret@hub.testingbot.com/wd/hub"), options ); // Generate two random numbers between 0 and 9 Random random = new Random(); int num1 = random.nextInt(10); int num2 = random.nextInt(10); WebElement firstNumber = driver.findElement(By.id("btn-" + num1)); WebElement secondNumber = driver.findElement(By.id("btn-" + num2)); WebElement plus = driver.findElement(By.id("btn-plus")); WebElement equal = driver.findElement(By.id("btn-equal")); firstNumber.click(); plus.click(); secondNumber.click(); equal.click(); WebElement resultElement = driver.findElement(By.id("calc-display")); String resultText = resultElement.getText(); // Verify the result if ((num1 + num2) != Integer.parseInt(resultText)) { throw new AssertionError("Test failed"); } // Quit the driver driver.quit(); } catch (Exception e) { e.printStackTrace(); } } } from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options import random # Set capabilities options = Options() options.set_capability("browserName", "electron") options.set_capability("platformName", "VENTURA") options.set_capability("browserVersion", "31") options.set_capability("tb:binary_location", "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app") options.set_capability("tb:app", "https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip") # Initialize the WebDriver connection to TestingBot driver = webdriver.Remote( command_executor="https://key:secret@hub.testingbot.com/wd/hub", options=options ) try: # Generate two random numbers between 0 and 9 num1 = random.randint(0, 9) num2 = random.randint(0, 9) # Find elements on the page first_number = driver.find_element(By.ID, f"btn-{num1}") second_number = driver.find_element(By.ID, f"btn-{num2}") plus = driver.find_element(By.ID, "btn-plus") equal = driver.find_element(By.ID, "btn-equal") # Perform operations first_number.click() plus.click() second_number.click() equal.click() # Get the result result_element = driver.find_element(By.ID, "calc-display") result_text = result_element.text # Verify the result assert (num1 + num2) == int(result_text), "Test failed" finally: driver.quit() const { Builder, By } = require('selenium-webdriver'); const { Options } = require('selenium-webdriver/chrome'); (async function example() { let driver; try { // Set capabilities let caps = { browserName: 'electron', platformName: 'VENTURA', browserVersion: '31', 'tb:binary_location': 'testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app', 'tb:app': 'https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-darwin-arm64-1.0.0.zip' }; driver = await new Builder() .usingServer('https://key:secret@hub.testingbot.com/wd/hub') .withCapabilities(caps) .build(); // Generate two random numbers between 0 and 9 const num1 = Math.floor(Math.random() * 10); const num2 = Math.floor(Math.random() * 10); const firstNumber = await driver.findElement(By.id(`btn-${num1}`)); const secondNumber = await driver.findElement(By.id(`btn-${num2}`)); const plus = await driver.findElement(By.id('btn-plus')); const equal = await driver.findElement(By.id('btn-equal')); // Perform operations await firstNumber.click(); await plus.click(); await secondNumber.click(); await equal.click(); // Get the result const resultElement = await driver.findElement(By.id('calc-display')); const resultText = await resultElement.getText(); // Verify the result if ((num1 + num2) !== parseInt(resultText)) { throw new Error('Test failed'); } } catch (error) { console.error('Error during test execution:', error); } finally { if (driver) { await driver.quit(); } } })(); using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using System; class SeleniumTest { static void Main(string[] args) { try { // Set capabilities var options = new ChromeOptions(); options.AddAdditionalChromeOption("browserName", "electron"); options.PlatformName = "VENTURA"; options.BrowserVersion = "31"; options.AddAdditionalChromeOption("tb:binary_location", "testingbot-electron-demo-app.app/Contents/MacOS/testingbot-electron-demo-app"); options.AddAdditionalChromeOption("tb:app", "https://testingbot.com/electron/mac-demo.zip"); var commandTimeout = TimeSpan.FromSeconds(200); IWebDriver driver = new RemoteWebDriver( new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options, commandTimeout ); // Generate two random numbers between 0 and 9 Random random = new Random(); int num1 = random.Next(0, 10); int num2 = random.Next(0, 10); IWebElement firstNumber = driver.FindElement(By.Id($"btn-{num1}")); IWebElement secondNumber = driver.FindElement(By.Id($"btn-{num2}")); IWebElement plus = driver.FindElement(By.Id("btn-plus")); IWebElement equal = driver.FindElement(By.Id("btn-equal")); // Perform operations firstNumber.Click(); plus.Click(); secondNumber.Click(); equal.Click(); // Get the result IWebElement resultElement = driver.FindElement(By.Id("calc-display")); string resultText = resultElement.Text; // Verify the result if ((num1 + num2) != int.Parse(resultText)) { throw new Exception("Test failed"); } // Quit the driver driver.Quit(); } catch (Exception ex) { Console.WriteLine($"Error during test execution: {ex.Message}"); } } } The example above will run the TestingBot Demo Electron app on a remote macOS machine. You can also choose to run the demo app on a remote Windows machine inside TestingBot's grid, please see the capabilities below. options = Selenium::WebDriver::Options.chrome options.browser_name = "electron" options.platform_name = "WIN10" options.browser_version = "31" options.add_option("tb:binary_location", "testingbot-electron-demo-app.exe") options.add_option("tb:app", "https://github.com/testingbot/testingbot-electron-demo-app/releases/download/v1.0.0/testingbot-electron-demo-app-win32-x64-1.0.0.zip") ## Configuring Electron tests To configure your Electron test with TestingBot, you need to supply 3 capabilities: - [app capability](https://testingbot.com#capability-app) - [binary\_location capability](https://testingbot.com#capability-binary) - Electron version capability Please use the `version` or `browserVersion` capability to indicate to TestingBot which version of Electron was used to create the final app that you are testing. TestingBot needs to know which version was used, so that we can map it to the Chromium version that is being used for that particular Electron version. For example, if you created your Electron app with Electron 31, you would need to provide `browserVersion: 31` as a capability. ## Electron Test Results Test results for each Electron test will be available in the TestingBot member dashboard. For each Electron test, you will get access to a video recording, generated log files and additional meta-data. These results are also available through the TestingBot [REST-API](https://testingbot.com/support/api) or by using one of the [TestingBot CI/CD plugins](https://testingbot.com/support/integrations/ci-cd). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/earlgrey # EarlGrey Testing TestingBot will release testing with EarlGrey in Q4 of 2025. Run your EarlGrey tests on physical Android devices in the cloud, on Samsung Galaxy devices, Pixels, Xiaomi and other Android devices. If you are interested in participating in our beta program, please contact us. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/maestro # Maestro Intro TestingBot provides a grid of remote iOS and Android physical devices + emulators, ready to run your Maestro flows. Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. You write flows, which are story-like tests, where you describe a specific flow in your mobile application. For example, you could have a login flow, or a checkout flow. Maestro is a relatively new test framework and offers several nice features, such as: - Built-in tolerance to flakiness: various mechanisms are added to try and prevent flaky tests, for example locators that have changed or moved positions. - Automatic waits: Maestro will automatically wait for certain conditions, which means you do not have to worry about delays, or adding sleep commands to your tests. - Declarative syntax, which is defined in Flow (`yaml`) files. ### Why TestingBot Cloud? TestingBot has been offering cloud-based testing since 2012 and has built a robust solution for Maestro cloud testing. Compared to other vendors and Maestro cloud, we offer the following improved features: - Run on any iOS version, both physical iOS devices and iOS simulators. - Test on **physical Android devices** , not just emulators (though that's also certainly possible) - No execution limit: your tests can run as long as they need - Apply various [options](https://testingbot.com/support/app-automate/maestro/options) such as setting orientation, geolocation options and more ## TestingBot CLI The easiest way to run Maestro tests on TestingBot is using our CLI tool. It handles uploading your app, flows and running tests in a single command. https://www.youtube.com/embed/MMWCkBgXFOU ### Installation npm install -g @testingbot/cli ### Authentication Authenticate using this command: testingbot login This opens your browser for authentication. After logging in, your credentials are saved to `~/.testingbot` and you can start using the CLI. #### Other Authentication Methods - **Command-line options** : `--api-key` and `--api-secret` - **Environment variables** : `TB_KEY` and `TB_SECRET` - **Config file** : Create `~/.testingbot` with content `key:secret` ### Quick Start Run Maestro tests with a single command: testingbot maestro app.apk flow.yml --device "Pixel 8" --deviceVersion "14" testingbot maestro app.ipa flow.yml --device "iPhone 16" --real-device The CLI will: 1. Upload your app to TestingBot 2. Upload and zip your flow files 3. Start the test run 4. Show real-time progress and results ## Upload Mobile App You will need to upload a mobile app to run tests with Maestro. The format of this file depends on which device type you'd like to test: - **iOS physical devices/simulators** : You can upload your `.ipa` or `.zip` file (for simulators, see [here how to prepare this zip file](https://testingbot.com/support/app-automate/help/prepare#simulator)). - **Android physical devices/emulators** : Upload the `.apk` file, which TestingBot will automatically install on the Android device. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, the app upload is handled automatically as part of the `testingbot maestro` command. Simply specify your app file as the first argument: testingbot maestro /path/to/app/file/sample-debug.apk ./flows Supported app formats: - **Android** : `.apk` - **iOS Physical Device** : `.ipa` - **iOS Simulator** : `.app`, `.zip` (zipped .app bundle) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/app" \ -F "file=@/path/to/app/file/sample-debug.zip" The API response will include an `id` response, which you can use in the other API calls. { "id": 4012 } ## Upload Maestro Flows To upload the Flows zip file, please follow the example below. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, flow files are automatically zipped and uploaded. You can specify: - A directory containing flow files - Individual `.yaml` or `.yml` files - A pre-zipped `.zip` file - Glob patterns (e.g., `./flows/**/*.yaml`) # Single directory testingbot maestro app.apk ./flows # Multiple directories testingbot maestro app.apk ./flows/smoke ./flows/regression # Individual flow files testingbot maestro app.apk login.yaml checkout.yaml # Pre-zipped flows testingbot maestro app.apk flows.zip Maestro Flow files are `.yaml` files which contain the actions that need to be performed. You can zip these together and upload to TestingBot by using the following command: zip -r flows.zip *.yaml Make sure all the necessary flows and sub flows are included in the zip file. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/tests" \ -F "file=@/path/to/app/file/flows.zip" Replace the `:id` with the identifier you received during the app upload call. (In this example 4012) Calling this multiple times with the same `:id` will overwrite the previously uploaded Flows zip file. ### Zip structure Maestro needs to know which flows it should run. If there are flow files (`.yaml` files) in the top-level directory of the zip file, it will run these flow files. You can also include a [config.yaml](https://testingbot.com/support/app-automate/maestro/options#config) file in the top-level directory of the zip file, to indicate which flows should be tested. For example, you can use the `**` annotation to indicate you want to run all flows, even if they are in separate sub-directories. flows: - "**" More information is available in the [Maestro Docs](https://docs.maestro.dev/cli/test-suites-and-reports#controlling-what-tests-to-include). ## Run Maestro tests Once you've uploaded both your app and Flows zip file, you can run the Maestro tests on the TestingBot cloud. Specify one or more capabilities, to indicate on which iOS simulators or Android devices you want to run your tests on. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the CLI to run tests with device selection options: # Basic usage with device selection testingbot maestro app.apk flow.yml --device "Pixel 8" --deviceVersion "14" # iOS simulator testingbot maestro app.zip ./flows --platform iOS --device "iPhone 16" --deviceVersion "26.0" # iOS physical device testingbot maestro app.ipa flow.yml --device "iPhone 16" --real-device # Android real device testingbot maestro app.apk flow.yml --device "Samsung Galaxy S24" --real-device # With additional options testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --name "Smoke Tests" \ --build "v2.1.0" # With CI/CD integration (Git metadata) testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --commit-sha "$COMMIT_SHA" \ --pull-request-id "$PR_NUMBER" \ --repo-owner "myorg" \ --repo-name "myapp" #### Device Options | Option | Description | | --- | --- | | `--device ` | Device name (e.g., "Pixel 9", "iPhone 16") | | `--platform ` | Platform: Android or iOS | | `--deviceVersion ` | OS version (e.g., "14", "18.0") | | `--real-device` | Use a real device instead of emulator/simulator | See the [Options page](https://testingbot.com/support/app-automate/maestro/options) for more configuration options. Select a device configuration below, then use the generated cURL command: ![OS Selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. Replace the `:id` with the identifier you received during the app upload call. (In this example 4012) When running Maestro tests on physical devices, a device could be occupied at times. You might want to use regex/wildcard patterns to target a broad range of devices. We offer special parameters which you can use to allocate a device: Regex Input | Result || `".*Galaxy.*"` | This will allocate any of the available Galaxy devices (phone or tablet) | | `"*"` | This will allocate a random available device, you can use this with the `deviceName` or `version`. | ## View Maestro Results The results of your Maestro tests will be available in the [TestingBot dashboard](https://testingbot.com/members). Each test result contains a video, test logs and other meta data generated during the test run. Maestro flows will be displayed, together with the steps that were taken during each flow. ![Maestro results](https://testingbot.com/assets/support/maestro/results-78a1591a85866ec01fa9a661652d9fd4cf0b24989743d73756e8a991157dd7be.png) You can also use the CLI or an API call to get back the result from the run(s): [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) By default, the CLI waits for test completion and displays real-time progress: testingbot maestro app.apk ./flows --device "Pixel 8" The CLI will show: - Upload progress for app and flows - Device allocation status - Live output from Maestro flows - Final pass/fail status #### Async Mode Use `--async` to start tests without waiting for results: testingbot maestro app.apk ./flows --device "Pixel 8" --async #### Download Artifacts Download test artifacts (logs, screenshots, video) after completion: testingbot maestro app.apk ./flows --device "Pixel 8" \ --download-artifacts \ --artifacts-output-dir ./artifacts curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro/:project_id" Replace the `:project_id` with the identifier you received during the app upload call. (In this example 4012) The response will contain a `success` boolean, indicating whether the test passed or failed. **Example response:** {"runs":[{"id":14019,"status":"DONE","capabilities":{"version":"15.0","deviceName":"Pixel 9","platformName":"Android"},"success":0,"report":"...","created_at":"2025-08-26T10:30:42.000Z","test":{"sessionId":"0255832ee646-e7620dc7d449-172937ccfc2d-175620408997-95145830","environment":{"name":"chrome","os":"Pixel 9 - 15.0","version":"15.0"}}}],"success":false,"version":"1.0","completed":true} You can poll this request to check if the tests have finished running. The `completed` boolean will be set to true when all tests have finished. ### JUnit Report All Maestro tests on TestingBot will by default run with a JUnit reporter. This report is accessible programmatically: [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Download the JUnit report automatically after test completion: # Download JUnit XML report testingbot maestro app.apk ./flows --device "Pixel 8" \ --report junit \ --report-output-dir ./reports The report will be saved to the specified directory with a filename based on the test run. curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro/:project_id/:run_id/junit_report" Replace the `:project_id` with the identifier you received during the app upload call. (In this example 4012) Replace the `:run_id` with the identifier for this run. The response will contain a `report` string value that contains the XML formatted JUnit report. ### Webhooks Because the Maestro tests run asynchronously, you might want to get notified when a test run has finished. You can poll the [results API](https://testingbot.com#results) or use the [Webhook integration](https://testingbot.com/support/integrations/webhooks) or [Slack integration](https://testingbot.com/support/integrations/slack) to get notified when a test run has finished. ## Example Maestro Flow Below is a simple example Flow, where we input two values in the TestingBot example app: - [Android Sample .apk](https://testingbot.com/appium/sample.apk) - [iOS Simulator Sample .zip](https://testingbot.com/appium/sample.zip) - [iOS Physical Sample .ipa](https://testingbot.com/appium/sample.ipa) appId: org.reactjs.native.example.SampleApp --- - launchApp - tapOn: id: inputA - longPressOn: id: inputA - tapOn: text: "Select All" - eraseText - inputText: "10" - tapOn: id: inputB - longPressOn: id: inputB - tapOn: text: "Select All" - eraseText - inputText: "5" - tapOn: id: sum - assertVisible: text: "15" ## Maestro Parallel Testing The TestingBot physical and virtual device grid is optimised to run many tests concurrently. You can run multiple Maestro flows simultaneously (in parallel), which will drastically shorten your total test duration. Depending on your subscription plan, you will be able to run 1 or more Maestro flows at the same time. If you exceed the threshold, additional Maestro flows will be queued until a slot becomes available. By default, each flow runs in a separate session. Make sure each flow can run isolated. If you don't want this, you can use the [--shard-split 1](https://testingbot.com#shard-split) option to run all flows in the same session. For example, let's assume you have an Automation Pro plan with 2 concurrent tests. And you want to run 10 Maestro tests, or run the same Maestro test on 10 different device configurations: - 2 Maestro tests will run simultaneously - The other 8 are waiting (queued) until one of the first two finishes - When a slot frees up, the next Maestro test in the queue will start to run - Finally, when all tests have run, you will see the results in the TestingBot dashboard Currently there is no limit to the amount of Maestro tests you can add to the queue. ## Grouping Flows When you have a large number of flows, you might want to split these flows across multiple test runs. This is also known as sharding. By default, each test runs separately in parallel on TestingBot. You can group flows together that should run in the same session by using the `--shard-split` option. # Shard flows across 3 parallel sessions testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --shard-split 3 You can also decide to run all flows in the same session by using the `--shard-split 1` option. # Shard flows across 3 parallel sessions testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --shard-split 1 ## Integrations TestingBot offers various [integrations](https://testingbot.com/support/integrations) which allow for connecting your Maestro tests with external services. For example; you can receive automated Slack messages each time a Maestro test runs or fails, or you can integrate Maestro testing with any CI/CD system. - [App Center](https://testingbot.com/support/integrations/appcenter) - [Bitrise](https://testingbot.com/support/integrations/ci-cd/bitrise) - [GitHub Actions](https://testingbot.com/support/integrations/ci-cd/github-actions) - [Jenkins CI](https://testingbot.com/support/integrations/ci-cd/jenkins) - [Jira](https://testingbot.com/support/integrations/jira) - [Slack](https://testingbot.com/support/integrations/slack) - [TeamCity CI](https://testingbot.com/support/integrations/ci-cd/teamcity) - [Webhooks](https://testingbot.com/support/integrations/webhooks) ## API TestingBot provides a [REST-API](https://testingbot.com/support/app-automate/maestro/api) to retrieve information about your Maestro projects and runs. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/maestro/api # Maestro API Overview TestingBot provides a REST API to upload apps, run Maestro flows, and retrieve information about your [Maestro projects and runs](https://testingbot.com/support/app-automate/maestro). In the documentation below, a Maestro project using a `:project_id` consists of a mobile application that was uploaded together with a zipped set of Maestro flow files. A Maestro project can have multiple test runs, depending on how many device configurations (capabilities) you specified when you [started the tests](https://testingbot.com/support/app-automate/maestro/api#run). All API endpoints require authentication using your TestingBot API key and secret, which you can obtain from the Member area. | Base URL | Authentication | | --- | --- | | `https://api.testingbot.com/v1/app-automate/maestro` | HTTP Basic Auth (API key:secret) | ## CLI Alternative For most use cases, we recommend using the [TestingBot CLI](https://testingbot.com/support/app-automate/maestro#cli) instead of the REST API directly. The CLI handles uploading your app, flows and running tests in a single command: # Install the CLI npm install -g @testingbot/cli # Authenticate testingbot login # Run Maestro tests (handles upload + run automatically) testingbot maestro app.apk ./flows --device "Pixel 8" --deviceVersion "14" The CLI provides: - Automatic app and flow uploads - Real-time progress and streaming output - Automatic report downloads - Simpler authentication Use the REST API directly when you need programmatic access or custom integration workflows. ## Upload App Upload your Android (.apk/.aab) or iOS (.ipa/.app) application to TestingBot. This creates a new Maestro project and returns a project ID. | Method | Endpoint | | --- | --- | | `POST` | `/app-automate/maestro/app` | #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `file` | file | Yes | The app file to upload (.apk, .aab, .ipa, .app or .zip) | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/app" \ -F "file=@/path/to/your/app.apk" #### Response { "id": 17876, "app": { "app_url": "https://...", "icon_url": "https://...", "app_version": "1.0.0", "bundle_id": "com.example.app", } } Save the returned `id` - you'll need it for uploading flows and running tests. ## Upload Maestro Flows Upload your Maestro flow files (as a .zip archive) to an existing project. This replaces any previously uploaded flows. | Method | Endpoint | | --- | --- | | `POST` | `/app-automate/maestro/:id/tests` | #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | integer | Yes | The project ID returned from the app upload | | `file` | file | Yes | A .zip file containing your Maestro flow YAML files | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/tests" \ -F "file=@/path/to/flows.zip" #### Response { "id": 17876, "flows": [ { "id": 123, "name": "login_flow", } ] } ## Run Maestro Tests Start running your Maestro flows on one or more devices. You can specify multiple device configurations to run tests in parallel. | Method | Endpoint | | --- | --- | | `POST` | `/app-automate/maestro/:id/run` | #### Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | integer | Yes | The project ID | | `capabilities` | array | Yes | Array of device configurations to run tests on | | `maestroOptions` | object | No | Additional Maestro options (version, env, flows, tags). See [Test Options](https://testingbot.com/support/app-automate/maestro/options). | | `shardSplit` | integer | 1 | Group flows into N chunks, each chunk running on a separate device. By default each flow runs in its own session on a device. | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{"capabilities":[{"platformName":"Android","version":"14","deviceName":"Pixel 8"}]}' \ -H "Content-Type: application/json" #### Response { "success": true, "id": 17876, "runs": [ { "id": 18809, "capabilities": { "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }, "flows": [ { "id": 123, "name": "login_flow", "report": "...", "requested_at": "2025-11-28T09:15:00.000Z", "completed_at": "2025-11-28T09:16:00.000Z", "status": "WAITING", "test_case_id": 456 } ] } ] } #### Error Responses | Status Code | Description | | --- | --- | | `429` | Insufficient minutes available. Please upgrade your account to continue running Maestro tests. | ## List Maestro Projects Retrieve a paginated list of all your Maestro projects. | Method | Endpoint | | --- | --- | | `GET` | `/app-automate/maestro` | #### Query Parameters | Name | Type | Default | Description | | --- | --- | --- | --- | | `offset` | integer | 0 | Number of records to paginate | | `count` | integer | 10 | Number of records to return | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro" #### Response { "data": [ { "id": 17876, "name": "Maestro Project 17876", "created_at": "2025-11-28T08:12:31.000Z", "updated_at": "2025-11-28T08:12:31.000Z", "completed": false, "app": { "app_url": "https://...", "icon_url": "https://...", "app_version": "2.7.50420", "bundle_id": "org.wikipedia" }, "flows_url": "https://...", "flows": [ { "id": 123, "name": "login_flow", } ], "runs": [18809, 18854, 18863, 18866] } ], "meta": { "offset": 0, "count": 10, "total": 25 } } ## Get Maestro Project Info Retrieve details about a specific Maestro project, including all its runs. | Method | Endpoint | | --- | --- | | `GET` | `/app-automate/maestro/:id` | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro/:id" #### Response { "runs": [ { "id": 18809, "status": "DONE", "capabilities": { "version": "16", "deviceName": "Pixel 9", "platformName": "Android" }, "success": 1, "report": "", "options": {}, "flows": [ { "id": 123, "name": "login_flow", "report": "...", "requested_at": "2025-11-28T09:15:00.000Z", "completed_at": "2025-11-28T09:16:00.000Z", "status": "WAITING", "test_case_id": 456 } ] } ], "success": true, "completed": true } #### Run Status Values | Status | Description | | --- | --- | | `WAITING` | Run is queued and waiting for a device | | `READY` | The test is running on the device | | `DONE` | Run has completed | | `FAILED` | Run failed to complete | ## Get Run Info Retrieve detailed information about a specific Maestro run. Use this to poll for completion status. | Method | Endpoint | | --- | --- | | `GET` | `/app-automate/maestro/:project_id/:run_id` | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro/:project_id/:run_id" Replace `:project_id` with your project ID and `:run_id` with the run ID. #### Response { "id": 18809, "status": "DONE", "capabilities": { "version": "16", "deviceName": "Pixel 9", "platformName": "Android" }, "flows": [ { "id": 123, "name": "login_flow", "report": "...", "requested_at": "2025-11-28T09:15:00.000Z", "completed_at": "2025-11-28T09:16:00.000Z", "status": "WAITING", "test_case_id": 456 } ], "success": 1, "report": "", "options": {}, "completed": true } Poll this endpoint to check if the test has finished. The `completed` field will be `true` when the run has completed. ## JUnit Report Retrieve the JUnit XML report for a completed Maestro run. This is useful for CI/CD integration. | Method | Endpoint | | --- | --- | | `GET` | `/app-automate/maestro/:project_id/:run_id/junit_report` | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/maestro/:project_id/:run_id/junit_report" #### Response { "junit_report": "..." } The `junit_report` field contains the XML-formatted JUnit report generated by Maestro. ## Stop Maestro Run Stop a currently running Maestro test. | Method | Endpoint | | --- | --- | | `POST` | `/app-automate/maestro/:project_id/:run_id/stop` | [cURL](https://testingbot.com#) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:project_id/:run_id/stop" #### Response { "success": true } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/maestro/options # Maestro Test Options When running Maestro tests on TestingBot, you can customize the test execution using various options. These options are passed when [starting a test run](https://testingbot.com/support/app-automate/maestro/api#run) via the API. Options are organized into two categories: - **maestroOptions** : Options specific to Maestro execution (version, environment variables, flows, tags) - **capabilities** : Device and test configuration options (device, orientation, locale, network, etc.) ## Quick Reference All available options at a glance: #### Maestro Options | Option | Type | Description | | --- | --- | --- | | `version` | string | Maestro CLI version to use (e.g., "2.0.10") | | `flows` | array | Specific flow files to run (e.g., ["login.yml", "checkout.yml"]) | | `env` | object | Environment variables to pass to flows | | `includeTags` | array | Only run flows with these tags | | `excludeTags` | array | Skip flows with these tags | | `shardSplit` | number | Split flows across N parallel sessions | | `commitSha` | string | Git commit SHA for CI/CD tracking | | `pullRequestId` | string | Pull request ID for CI/CD tracking | | `repoName` | string | Repository name (e.g., GitHub repo slug) | | `repoOwner` | string | Repository owner (e.g., GitHub org or username) | #### Capability Options | Option | Type | Description | | --- | --- | --- | | `platformName` | string | Platform: "Android" or "iOS" (required) | | `version` | string | OS version (required) | | `deviceName` | string | Device name (required) | | `name` | string | Test name shown in dashboard | | `build` | string | Build name for grouping tests | | `orientation` | string | "PORTRAIT" (default) or "LANDSCAPE" | | `locale` | string | Device locale (e.g., "en\_US", "de\_DE") | | `timeZone` | string | Device timezone (e.g., "America/New\_York") | | `throttle_network` | string | Network preset: "Edge", "3G", "4G", "airplane" | | `testingbot.geoCountryCode` | string | Route traffic through specific country (ISO code) | ## Set Maestro Version By default, TestingBot runs your Maestro flows with the latest version of the Maestro CLI. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --maestro-version "2.0.10" If you need a specific version for compatibility, specify the `version` option in `maestroOptions`. | Option | Type | Example | | --- | --- | --- | | `maestroOptions.version` | string | "2.0.10" | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "maestroOptions": { "version": "2.0.10" }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" Replace `:id` with your project ID from the [app upload](https://testingbot.com/support/app-automate/maestro/api#uploadApp). ## Select Specific Flows By default, TestingBot runs all flow files in your zip archive. To run only specific flows, use the option below. #### Use Cases - Run a subset of flows for faster feedback during development - Execute specific test scenarios without modifying your test suite - Re-run failed flows without running the entire suite [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) With the CLI, you specify flows directly as arguments: # Run specific flow files testingbot maestro app.apk login.yml checkout.yml --device "Pixel 8" # Run flows from a specific directory testingbot maestro app.apk ./flows/smoke --device "Pixel 8" # Mix directories and individual files testingbot maestro app.apk ./flows/smoke login.yml --device "Pixel 8" | Option | Type | Example | | --- | --- | --- | | `maestroOptions.flows` | array of strings | `["login.yml", "checkout.yml"]` | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "maestroOptions": { "flows": ["login.yml", "checkout.yml"] }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" ## Environment Variables Pass environment variables to your Maestro flows using the `env` option. This is useful for configuration that varies between environments (staging, production) or for sensitive data like API keys. #### Use Cases - **Environment-specific URLs** : Point to staging or production backends - **Test credentials** : Pass login credentials securely via CI/CD - **Feature flags** : Enable or disable features during tests - **App identifiers** : Specify package names or bundle IDs dynamically [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the `-e` or `--env` flag (can be repeated): testingbot maestro app.apk ./flows --device "Pixel 8" \ -e API_URL=https://staging.example.com \ -e TEST_USER=testuser@example.com \ -e TEST_PASSWORD=secret123 | Option | Type | Example | | --- | --- | --- | | `maestroOptions.env` | object | `{"API_URL": "https://staging.example.com"}` | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "maestroOptions": { "env": { "API_URL": "https://staging.example.com", "TEST_USER": "testuser@example.com", "TEST_PASSWORD": "secret123" } }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" #### Using Variables in Your Flows Reference environment variables in your Maestro flow files using the `${VARIABLE_NAME}` syntax: appId: com.example.app --- - launchApp - inputText: text: "${TEST_USER}" - tapOn: "Next" - inputText: text: "${TEST_PASSWORD}" - tapOn: "Login" **Best Practice:** Never commit sensitive values like passwords or API keys to your repository. Pass them as environment variables through your CI/CD pipeline. ## Include Tags Run only flows that have specific tags. This is equivalent to Maestro's `--include-tags` option. #### Adding Tags to Flows Add tags to your flow files using the `tags` property: appId: com.example.app tags: - smoke - login --- - launchApp - tapOn: "Login" [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the `--include-tags` flag with comma-separated tags: testingbot maestro app.apk ./flows --device "Pixel 8" \ --include-tags "smoke,critical" | Option | Type | Example | | --- | --- | --- | | `maestroOptions.includeTags` | array of strings | `["smoke", "critical"]` | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "maestroOptions": { "includeTags": ["smoke", "critical"] }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" ## Exclude Tags Skip flows that have specific tags. This is equivalent to Maestro's `--exclude-tags` option. #### Use Cases - Skip slow tests during development for faster feedback - Exclude known flaky tests from CI pipelines - Skip platform-specific tests (e.g., exclude "ios-only" when running on Android) [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the `--exclude-tags` flag with comma-separated tags: testingbot maestro app.apk ./flows --device "Pixel 8" \ --exclude-tags "slow,flaky" | Option | Type | Example | | --- | --- | --- | | `maestroOptions.excludeTags` | array of strings | `["slow", "flaky"]` | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "maestroOptions": { "excludeTags": ["slow", "flaky"] }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" ## IP Geolocation Test your app from different geographic locations using TestingBot's GeoIP feature. Traffic from the device will route through an IP address in the specified country. #### Use Cases - Test geo-restricted content or features - Verify location-based pricing or currency display - Test localized content delivery [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.zip ./flows \ --platform iOS \ --device "iPhone 15" \ --deviceVersion "17.2" \ --geo-country-code "DE" | Option | Type | Example | | --- | --- | --- | | `testingbot.geoCountryCode` | string (ISO code) | `"DE", "US", "JP"` | curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "17.2", "deviceName": "iPhone 15", "testingbot.geoCountryCode": "DE" }] }' \ -H "Content-Type: application/json" See the full list of [available country codes](https://testingbot.com/support/web-automate/selenium/test-options#geo). ## Network Throttling Simulate different network conditions to test how your app performs under various connectivity scenarios. | Option | Type | Example | | --- | --- | --- | | `throttle_network` | string | "4G", "3G", "Edge", "airplane" | #### Network Presets | Preset | Download | Upload | Latency | Use Case | | --- | --- | --- | --- | --- | | `4G` | 18 Mbps | 9 Mbps | 100ms | Standard mobile connection | | `3G` | 400 Kbps | 100 Kbps | 100ms | Slower mobile network | | `Edge` | 250 Kbps | 150 Kbps | 300ms | Poor connectivity areas | | `airplane` | 0 | 0 | - | No connectivity (offline mode) | | `disable` | - | - | - | Restore full connectivity | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.zip ./flows \ --platform iOS \ --device "iPhone 15" \ --deviceVersion "17.2" \ --throttle-network "3G" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "17.2", "deviceName": "iPhone 15", "throttle_network": "3G" }] }' \ -H "Content-Type: application/json" ## Test Name Set a custom name for your test that appears in the TestingBot dashboard. This makes it easier to identify specific test runs. | Option | Type | Example | | --- | --- | --- | | `name` | string | "Login Flow - Smoke Test" | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.zip ./flows \ --platform iOS \ --device "iPhone 15" \ --deviceVersion "17.2" \ --name "Login Flow - Smoke Test" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "17.2", "deviceName": "iPhone 15", "name": "Login Flow - Smoke Test" }] }' \ -H "Content-Type: application/json" ## Build Grouping Group multiple test runs under a single build name. This is useful for organizing tests that belong to the same CI/CD pipeline run or release version. | Option | Type | Example | | --- | --- | --- | | `build` | string | "Release 2.5.0" | #### Benefits - View aggregated pass/fail statistics for all tests in a build - Track test results across different device configurations - Easily identify which builds introduced failures [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.ipa ./flows \ --platform iOS \ --device "iPhone 17" \ --real-device \ --build "Release 2.5.0" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "26.0", "deviceName": "iPhone 17", "realDevice": true, "build": "Release 2.5.0" }] }' \ -H "Content-Type: application/json" ## Shard Split Group your Maestro flows into chunks, which will run across multiple parallel sessions for faster execution. For example you have 3 parallel slots and 9 tests, but you want to split this test suite into 3 chunks of tests and run them in parallel on connected devices, then you would use `shardSplit` set to 3. | Option | Type | Example | | --- | --- | --- | | `shardSplit` | number | 1 | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) # Split flows across 3 parallel sessions - without this each flow would run in its own session testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --shard-split 3 curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "shardSplit": 3, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" ## CI/CD Integration Pass Git and repository metadata to associate test runs with specific commits and pull requests. This information appears in the TestingBot dashboard and can be used for tracking and debugging. | Option | Type | Description | | --- | --- | --- | | `commitSha` | string | Git commit SHA associated with this test run | | `pullRequestId` | string | Pull request ID this test run originated from | | `repoName` | string | Repository name (e.g., GitHub repo slug) | | `repoOwner` | string | Repository owner (e.g., GitHub organization or username) | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) # Pass Git metadata for CI/CD tracking testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --commit-sha "abc123def456" \ --pull-request-id "42" \ --repo-owner "myorg" \ --repo-name "myapp" #### GitHub Actions Example testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --commit-sha "${{ github.sha }}" \ --pull-request-id "${{ github.event.pull_request.number }}" \ --repo-owner "${{ github.repository_owner }}" \ --repo-name "${{ github.event.repository.name }}" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "meta": { "commitSha": "abc123def456", "pullRequestId": "42", "repoName": "myapp", "repoOwner": "myorg" }, "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8" }] }' \ -H "Content-Type: application/json" ## Device Orientation Set the device orientation at the start of your test. | Option | Type | Values | Default | | --- | --- | --- | --- | | `orientation` | string | `"PORTRAIT", "LANDSCAPE"` | PORTRAIT | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.apk ./flows \ --device "Pixel 8" \ --deviceVersion "14" \ --orientation LANDSCAPE curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "Android", "version": "14", "deviceName": "Pixel 8", "orientation": "LANDSCAPE" }] }' \ -H "Content-Type: application/json" ## Device Timezone Set the device timezone for your test. Useful for testing time-sensitive features. | Option | Type | Example | | --- | --- | --- | | `timeZone` | string (IANA) | `"America/New_York", "Europe/London", "Asia/Tokyo"` | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.zip ./flows \ --platform iOS \ --device "iPhone 15" \ --deviceVersion "17.2" \ --timezone "America/New_York" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "17.2", "deviceName": "iPhone 15", "timeZone": "America/New_York" }] }' \ -H "Content-Type: application/json" See the [full list of timezone identifiers](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). ## Device Locale Set the device locale to test localized content and formatting. The locale affects language, date formats, number formats, and currency display. | Option | Type | Format | Example | | --- | --- | --- | --- | | `locale` | string | language\_COUNTRY | `"de_DE", "fr_CA", "ja_JP"` | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot maestro app.zip ./flows \ --platform iOS \ --device "iPhone 15" \ --deviceVersion "17.2" \ --device-locale "de_DE" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/maestro/:id/run" \ -d '{ "capabilities": [{ "platformName": "iOS", "version": "17.2", "deviceName": "iPhone 15", "locale": "de_DE" }] }' \ -H "Content-Type: application/json" #### Common Locale Codes | Region | Locale Code | | --- | --- | | English (US) | `en_US` | | English (UK) | `en_GB` | | German (Germany) | `de_DE` | | French (France) | `fr_FR` | | French (Canada) | `fr_CA` | | Spanish (Spain) | `es_ES` | | Spanish (Mexico) | `es_MX` | | Japanese | `ja_JP` | | Chinese (Simplified) | `zh_CN` | | Chinese (Traditional) | `zh_TW` | | Korean | `ko_KR` | | Portuguese (Brazil) | `pt_BR` | | Italian | `it_IT` | | Dutch | `nl_NL` | | Russian | `ru_RU` | | Arabic | `ar_SA` | | Hindi | `hi_IN` | ## Maestro config.yaml You can include a `config.yaml` file in your [Maestro flows zip file](https://testingbot.com/support/app-automate/maestro#uploadSuite). This configuration file lets you define options that apply to all your flows. #### Supported config.yaml Options | Option | Description | | --- | --- | | `includeTags` | Only run flows with these tags | | `excludeTags` | Skip flows with these tags | | `env` | Environment variables available in all flows | #### Example config.yaml env: API_URL: https://api.example.com DEBUG: "true" includeTags: - smoke - critical ## TestingBot Tunnel Use [TestingBot Tunnel](https://testingbot.com/support/tunnel) to allow your app to access private or staging backend servers during tests. #### Use Cases - Test against staging APIs not accessible from the public internet - Access localhost services running on your machine - Test with private databases or internal services When a TestingBot Tunnel is active on your account, Maestro tests automatically route traffic through it. No additional configuration is needed. To start a tunnel, download and run the [TestingBot Tunnel](https://testingbot.com/support/tunnel) client before starting your tests. ## CLI Reference When using the [TestingBot CLI](https://testingbot.com/support/app-automate/maestro#cli), these options are available as command-line flags: #### Device Options | CLI Option | Description | | --- | --- | | `--device ` | Device name (e.g., "Pixel 9", "iPhone 16") | | `--platform ` | Platform: Android or iOS | | `--deviceVersion ` | OS version (e.g., "14", "17.2") | | `--real-device` | Use a real device instead of emulator/simulator | | `--orientation ` | Screen orientation: PORTRAIT or LANDSCAPE | | `--device-locale ` | Device locale (e.g., "en\_US", "de\_DE") | | `--timezone ` | Timezone (e.g., "America/New\_York") | #### Test Configuration | CLI Option | Description | | --- | --- | | `--name ` | Test name for dashboard identification | | `--build ` | Build identifier for grouping test runs | | `--include-tags ` | Only run flows with these tags (comma-separated) | | `--exclude-tags ` | Exclude flows with these tags (comma-separated) | | `-e, --env ` | Environment variable for flows (can be repeated) | | `--maestro-version ` | Maestro version to use (e.g., "2.0.10") | | `--shard-split ` | Split flows into N chunks, each chunk running on a separate device | #### CI/CD Integration | CLI Option | Description | | --- | --- | | `--commit-sha ` | Git commit SHA associated with this test run | | `--pull-request-id ` | Pull request ID this test run originated from | | `--repo-name ` | Repository name (e.g., GitHub repo slug) | | `--repo-owner ` | Repository owner (e.g., GitHub organization or username) | #### Network & Location | CLI Option | Description | | --- | --- | | `--throttle-network ` | Network throttling: 4G, 3G, Edge, airplane, or disable | | `--geo-country-code ` | Geographic IP location (ISO country code, e.g., "US", "DE") | #### Output Options | CLI Option | Description | | --- | --- | | `--async` | Start tests and exit without waiting for results | | `-q, --quiet` | Suppress progress output | | `--report ` | Download report after completion: html or junit | | `--report-output-dir ` | Directory to save reports | | `--download-artifacts` | Download test artifacts (logs, screenshots, video) | | `--artifacts-output-dir ` | Directory to save artifacts zip | #### Advanced Options | CLI Option | Description | | --- | --- | | `--ignore-checksum-check` | Skip checksum verification and always upload the app | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso # Espresso Testing TestingBot provides access to Android physical devices and Android emulators, capable of running your Android Espresso tests. [Espresso](https://developer.android.com/training/testing/espresso) is a mobile automation framework from Google, designed to run UI tests for Android applications. Using Espresso in combination with TestingBot's Android cloud service is very straightforward: - Upload your native mobile Android app, together with the Espresso test apk file. These are created with either Java or Kotlin. - Specify on which devices you want to run the Espresso tests. - Retrieve the results of the Espresso tests. ## Getting Started To get started, please follow the steps below: 1. You will need a `key` and `secret` to connect to the TestingBot grid. These credentials are available in the [TestingBot member area](https://testingbot.com/members). 2. Espresso tests require a separate `apk` file for testing. So you will need to upload both the app (`.apk` or `.aab` file) and the test file (`.apk`). You can also use the [TestingBot Espresso Demo App](https://github.com/testingbot/android-espresso-demo-app) to give the Espresso Cloud Testing functionality a try. ## TestingBot CLI The easiest way to run Espresso tests on TestingBot is using our CLI tool. It handles uploading your app, test APK, and running tests in a single command. ### Installation npm install -g @testingbot/cli ### Authentication Authenticate using this command: testingbot login This opens your browser for authentication. After logging in, your credentials are saved to `~/.testingbot` and you can start using the CLI. #### Other Authentication Methods - **Command-line options** : `--api-key` and `--api-secret` - **Environment variables** : `TB_KEY` and `TB_SECRET` - **Config file** : Create `~/.testingbot` with content `key:secret` ### Quick Start Run Espresso tests with a single command: testingbot espresso app.apk app-test.apk --device "Pixel 8" --platform-version "14" testingbot espresso app.apk app-test.apk --device "Samsung Galaxy S24" --real-device The CLI will: 1. Upload your app APK to TestingBot 2. Upload your test APK 3. Start the test run 4. Show real-time progress and results ## Upload Android App To run Android Espresso tests on TestingBot, you will first have to upload your `.apk` or `.aab` file to TestingBot Storage. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, the app upload is handled automatically as part of the `testingbot espresso` command. Simply specify your app APK file as the first argument: testingbot espresso /path/to/app/Application-debug.apk /path/to/test/Application-debug-test.apk --device "Pixel 8" Alternatively, you can use the `--app` option: testingbot espresso --app /path/to/app/Application-debug.apk --test-app /path/to/test/Application-debug-test.apk --device "Pixel 8" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/app" \ -F "file=@/path/to/app/file/Application-debug.apk" The API response will include an `id` response, which you can use in the other API calls. { "id": 4012 } ## Upload Espresso Test Suite You can now upload the `.apk` file containing the Espresso tests. The upload process is similar to the [app upload](https://testingbot.com#upload) process. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, the test APK upload is handled automatically. Specify your test APK as the second argument: testingbot espresso app.apk app-test.apk --device "Pixel 8" Or use the `--test-app` option: testingbot espresso --app app.apk --test-app app-test.apk --device "Pixel 8" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/tests" \ -F "file=@/path/to/app/file/Application-debug-test.apk" Replace the `:id` with the identifier you received during the app upload call. ## Specify devices You can specify one or more Android device capabilities with your API call. These capabilities can target either Android emulators, or physical Android devices. ![Android OS selected](https://testingbot.com/assets/environments/svg/android-1b3d235e17522e2238e1c55b4e9cdd41219f653cd958ea065877d3813f32ffc3.svg)Android 16.0›Pixel 9 Loading environments... Please wait while we load the available browsers and platforms. We offer special parameters which you can use to allocate a device: Regex Input | Result || `"Pixel.*"` | This will allocate any available Pixel device (phone) | | `"*"` | This will allocate a random available Android device | | `"Samsung [20-21]"` | This will allocate either an Samsung 20 or 21 | Some Examples: // find any Samsung Galaxy, except 23 -d '{"capabilities":[{"deviceName":"^(Galaxy.*)(?!23)$", "platformName":"Android", "realDevice": true}]}' // find any device which name starts with Pixel -d '{"capabilities":[{"deviceName":"Pixel.*", "platformName":"Android", "realDevice": true}]}' ### Tablet Only You can specify the `tabletOnly` capability when you only want to allocate a tablet device. ### Phone Only You can specify the `phoneOnly` capability when you only want to allocate a phone device. -d '{"capabilities":[{"deviceName":"*", "tabletOnly": true, "platformName":"Android", "realDevice": true}]}' -d '{"capabilities":[{"deviceName":"*", "phoneOnly": true, "platformName":"Android", "realDevice": true}]}' ## Run Espresso Tests Now that you have uploaded both your Android application and the Espresso test suite, you can run your first Espresso test on the TestingBot cloud. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the CLI to run tests with device selection options: # Basic usage with device selection testingbot espresso app.apk app-test.apk --device "Pixel 8" --platform-version "14" # Real device testingbot espresso app.apk app-test.apk --device "Samsung Galaxy S24" --real-device # With test name and build identifier testingbot espresso app.apk app-test.apk \ --device "Pixel 8" \ --platform-version "14" \ --name "Smoke Tests" \ --build "v2.1.0" #### Device Options | Option | Description | | --- | --- | | `--device ` | Device name (e.g., "Pixel 8", "Samsung.\*") | | `--platform-version ` | Android version (e.g., "12", "13", "14") | | `--real-device` | Use a real device instead of emulator | | `--tablet-only` | Only allocate tablet devices | | `--phone-only` | Only allocate phone devices | #### Test Filtering # Run specific test classes testingbot espresso app.apk app-test.apk \ --device "Pixel 8" \ --class "com.example.LoginTest,com.example.HomeTest" # Run tests with specific annotations testingbot espresso app.apk app-test.apk \ --device "Pixel 8" \ --annotation "com.example.SmokeTest" \ --size "small,medium" # Exclude specific test classes testingbot espresso app.apk app-test.apk \ --device "Pixel 8" \ --not-class "com.example.SlowTest" #### Test Filtering Options | Option | Description | | --- | --- | | `--class ` | Run tests in specific classes (comma-separated fully qualified names) | | `--not-class ` | Exclude tests in specific classes | | `--package ` | Run tests in specific packages (comma-separated) | | `--not-package ` | Exclude tests in specific packages | | `--annotation ` | Run tests with specific annotations (comma-separated) | | `--not-annotation ` | Exclude tests with specific annotations | | `--size ` | Run tests by size: small, medium, large (comma-separated) | #### Network & Location # With network throttling and geolocation testingbot espresso app.apk app-test.apk \ --device "Pixel 8" \ --throttle-network "3G" \ --geo-location "DE" \ --language "de" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{"capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Replace the `:id` with the identifier you received during the app upload call. The API response will include a `success` response, indicating if the tests will start or if an error occurred. { "success": true } ## View Espresso Test Results You will now see a test appear in the [TestingBot dashboard](https://testingbot.com/members), together with a video, test logs and other metadata. You can also use the CLI or an API call to get the results from the run(s): [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) By default, the CLI waits for test completion and displays real-time progress: testingbot espresso app.apk app-test.apk --device "Pixel 8" The CLI will show: - Upload progress for app and test APK - Device allocation status - Live output from Espresso tests - Final pass/fail status #### Async Mode Use `--async` to start tests without waiting for results: testingbot espresso app.apk app-test.apk --device "Pixel 8" --async #### Download JUnit Report Download the JUnit report after test completion: testingbot espresso app.apk app-test.apk --device "Pixel 8" \ --report junit \ --report-output-dir ./reports curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/espresso/:id" Replace the `:id` with the identifier you received during the app upload call. The API response will include a response indicating the current state of the Espresso test results. { "runs": [ { "status": "DONE", "capabilities": { "version": "12", "deviceName": "Pixel 6", "platformName": "Android" }, "success": false, "test": { "sessionId": "30f6eild082c3-804f3c0ec2df-a18b2d431ffb-169920992163-48455547", "environment": { "name": "chrome", "os": "Pixel 6 - 12.0", "version": "12.0" } } } ], "version": "1.0" } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/instrumentation # Espresso Instrumentation Logs Instrumentation logs are logs generated by Android Espresso. These logs list all the steps that were performed during the test, with any errors or meta data available from the Android Espresso test runner (usually `AndroidJUnitRunner`). These logs are available in the [TestingBot dashboard](https://testingbot.com/members) as well as through the [REST API](https://testingbot.com/support/api). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/filter # Filter Espresso Test Cases By default, TestingBot will execute all tests present in the Espresso `.apk`. The Espresso test runner (which is usually **AndroidJUnitRunner** ) provides multiple options to filter test cases for execution. You might want to use these filter options for specific use cases, such as: - Run only specific tests for a bugfix. - Only run a subset of tests, for quick smoke testing. Instead of waiting on all your Espresso tests. - Run specific tests for specific environments (production, staging, ...) Below you'll find the different filter options that TestingBot and Espresso provide. - [class](https://testingbot.com#class): will run all tests in a specific class - [notClass](https://testingbot.com#notClass): will run all tests except the tests in a particular class - [size](https://testingbot.com#size): will run a specific test size annotated with `SmallTest`, `MediumTest` or `LargeTest` - [package](https://testingbot.com#package): will run all tests in a specific Java package - [notPackage](https://testingbot.com#notPackage): will run all tests except the tests in a specific package - [annotation](https://testingbot.com#annotation): will run all tests with a specific annotation - [notAnnotation](https://testingbot.com#notAnnotation): will run all tests except the tests with a specific annotation - [numShards](https://testingbot.com#shards): filter test run to a shard of all tests, where numShards is an integer greater than 0 and shardIndex is an integer between 0 (inclusive) and numShards ## class Filter To only run Espresso tests for a specific `class`, you can use the class option. You can pass a list of fully qualified Java class names. See the example below. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --class "com.android.app.one,com.android.app.two" This will start an Espresso test session on the specified device and only run tests for the classes specified. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "class": ["com.android.app.one", "com.android.app.two"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" This call with start an Espresso test Session on the specific device and only run the Espresso tests for the classNames specified. ## notClass Filter Use the `notClass` option to run all Espresso tests except for the tests in the classes specified with this option. You can pass a list of fully qualified Java class names. See the example below. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --not-class "com.android.app.one,com.android.app.two" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "notClass": ["com.android.app.one", "com.android.app.two"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## size Filter The `size` option allows you to specify which tests you want to run, depending on the annotated size: `SmallTest`, `MediumTest` or `LargeTest` You can pass an array of sizes, see below for an example. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --size "small,medium" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "size": ["small", "medium"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## package Filter The `package` filter allows you to specify for which package the Espresso tests should run. You can pass an array of packages, see below for an example. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --package "com.android.one,com.android.two" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "package": ["com.android.one", "com.android.two"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## notPackage Filter The `notPackage` filter allows you to indicate that Espresso tests should run for everything except for the packages defined. You can pass an array of packages, see below for an example. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --not-package "com.android.one,com.android.two" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "notPackage": ["com.android.one", "com.android.two"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## annotation Filter The `annotation` filter will run tests annotated with the field (or fields) you specified. You can pass an array of annotations, see below for an example. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --annotation "com.android.foo.MyAnnotation,com.android.foo.MyAnnotationTwo" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "annotation": ["com.android.foo.MyAnnotation", "com.android.foo.MyAnnotationTwo"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## notAnnotation Filter The `notAnnotation` filter will run all tests except those annotated with the field (or fields) you specified. You can pass an array of notAnnotations, see below for an example. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --not-annotation "com.android.foo.MyAnnotation,com.android.foo.MyAnnotationTwo" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "notAnnotation": ["com.android.foo.MyAnnotation", "com.android.foo.MyAnnotationTwo"] }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/options # Set Espresso Test Runner By default, TestingBot will run your Espresso tests with `${packageName}/androidx.test.runner.AndroidJUnitRunner`. If you have defined your own `testInstrumentationRunner`, you can pass this custom runner during the start Espresso call: [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --test-runner "${packageName}/customTestRunner" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "testRunner": "${packageName}/customTestRunner" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Replace the `:id` with the identifier you received during the app upload call. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/screenshots # Capturing Espresso Screenshots Espresso does not have a built-in way to capture screenshots during test automation. You can however achieve this by using two options: - **Native Screenshot grabbing** Use native Java or Kotlin code to take a screenshot of the device, and save it on the device. Once the test is completed, you can fetch the image through `ADB`, or if you run it via TestingBot, the screenshot will appear on the [test result page](https://testingbot.com#view). - **Using the Spoon library** The [Square Screenshots feature](https://square.github.io/spoon/#screenshots) is part of the Spoon Library. It will take screenshots during your Espresso tests, but only for Android devices with a version of Android 10 or lower. [Using Native Screenshot](https://testingbot.com#)[Using Spoon Library](https://testingbot.com#) 1. **Add the native screenshots file to your project** You can see the implementation of Native Screenshots in the [TestingBot Espresso Demo App](https://github.com/testingbot/android-espresso-demo-app/blob/main/app/src/androidTest/java/com/testingbot/calculator/NativeScreenshot.java). package com.testingbot.calculator; import android.graphics.Bitmap; import android.os.Build; import android.os.Environment; import androidx.test.runner.screenshot.BasicScreenCaptureProcessor; import androidx.test.runner.screenshot.ScreenCapture; import androidx.test.runner.screenshot.Screenshot; import java.io.File; import java.io.IOException; import java.util.regex.Pattern; public final class NativeScreenshot { private static String methodName; private static String className; private static final Pattern SCREENSHOT_NAME_VALIDATION = Pattern.compile("[a-zA-Z0-9_-]+"); private NativeScreenshot() {} /** * Captures screenshot using Androidx Screenshot library and stores in the filesystem. * If there is any runtime exception while capturing screenshot, the method throws * Exception and the test might fail if exception is not handled properly. * @param screenshotName a screenshot identifier * @return path to the screenshot file */ public static String capture(String screenshotName) { StackTraceElement testClass = findTestClassTraceElement(Thread.currentThread().getStackTrace()); className = testClass.getClassName().replaceAll("[^A-Za-z0-9._-]", "_"); methodName = testClass.getMethodName(); EspressoScreenCaptureProcessor screenCaptureProcessor = new EspressoScreenCaptureProcessor(); if (!SCREENSHOT_NAME_VALIDATION.matcher(screenshotName).matches()) { throw new IllegalArgumentException("ScreenshotName must match " + SCREENSHOT_NAME_VALIDATION.pattern() + "."); } else { ScreenCapture capture = Screenshot.capture(); capture.setFormat(Bitmap.CompressFormat.PNG); capture.setName(screenshotName); try { return screenCaptureProcessor.process(capture); } catch (IOException e) { throw new RuntimeException("Unable to capture screenshot.", e); } } } /** * Extracts the currently executing test's trace element based on the test runner * or any framework being used. * @param trace stacktrace of the currently running test * @return StackTrace Element corresponding to the current test being executed. */ private static StackTraceElement findTestClassTraceElement(StackTraceElement[] trace) { for(int i = trace.length - 1; i >= 0; --i) { StackTraceElement element = trace[i]; if ("android.test.InstrumentationTestCase".equals(element.getClassName()) && "runMethod".equals(element.getMethodName())) { return extractStackElement(trace, i); } if ("org.junit.runners.model.FrameworkMethod$1".equals(element.getClassName()) && "runReflectiveCall".equals(element.getMethodName())) { return extractStackElement(trace, i); } if ("cucumber.runtime.model.CucumberFeature".equals(element.getClassName()) && "run".equals(element.getMethodName())) { return extractStackElement(trace, i); } } throw new IllegalArgumentException("Could not find test class!"); } /** * Based on the test runner or framework being used, extracts the exact traceElement. * @param trace stacktrace of the currently running test * @param i a reference index * @return trace element based on the index passed */ private static StackTraceElement extractStackElement(StackTraceElement[] trace, int i) { int testClassTraceIndex = Build.VERSION.SDK_INT >= 23 ? i - 2 : i - 3; return trace[testClassTraceIndex]; } private static class EspressoScreenCaptureProcessor extends BasicScreenCaptureProcessor { private static final String SCREENSHOT = "screenshots"; EspressoScreenCaptureProcessor() { File screenshotDir = new File(String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)), SCREENSHOT); File classDir = new File(screenshotDir, className); mDefaultScreenshotPath = new File(classDir, methodName); } /** * Converts the filename to a standard path to be stored on device. * Example: "post_addition" converts to "1648038895211_post_addition" * which is later suffixed by the file extension i.e. png. * @param filename a screenshot identifier * @return custom filename format */ @Override protected String getFilename(String filename) { return System.currentTimeMillis() + "_" + filename; } } } 2. **Modify your Espresso test scripts to take screenshots** You can call the `NativeScreenshot.capture("tag")` method to capture screenshots in your Espresso tests. The `tag` can be used to provide a name to the screenshot (usually you would use the testname for this). @Test public void ensureCalculatorWorks() { onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.buttonAdd)).perform(click()); onView(withId(R.id.buttonTwo)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("3"))); NativeScreenshot.capture(mainActivity, "ensureCalculatorWorks"); } 3. **Android 11 and higher** For Android 11 and higher, make sure to add the following `RuleChain` to your Espresso test: @Rule public RuleChain screenshotRule = RuleChain .outerRule(GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)) .around(activityScenarioRule); 1. **Add the required dependencies to your project** See the [Spoon Documentation](https://github.com/square/spoon#download) on how to add Spoon to your project. You can either use a `JAR` or use `Maven`. 2. **Change storage permissions** If you do not yet have the `WRITE_EXTERNAL_STORAGE` permission in your `AndroidManifest.xml`, please add it. It will allow Spoon to save the screenshots on your device. ... If the targetSdk for your app is using Android 10 (level 29), please make sure to add `android:requestLegacyExternalStorage="true"` in the Application tag of your `AndroidManifest.xml` file. 3. **Modify your Espresso test scripts to take screenshots** You can call the `Spoon.screenshot(activityName, tag)` method to capture screenshots in your Espresso tests. The `tag` can be used to provide a name to the screenshot (usually you would use the testname for this). @Test public void ensureCalculatorWorks() { onView(withId(R.id.buttonOne)).perform(click()); onView(withId(R.id.buttonAdd)).perform(click()); onView(withId(R.id.buttonTwo)).perform(click()); onView(withId(R.id.editText)).check(matches(withText("3"))); Spoon.screenshot(mainActivity, "ensureCalculatorWorks"); } ## Viewing Espresso Screenshots The Espresso tests that you run on TestingBot will appear automatically in the TestingBot dashboard. If screenshots were generated during the test, they will be added on the Espresso test result page. Additionally, these screenshots will also be available for download through our [REST API](https://testingbot.com/support/api). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/set-ip-geolocation # Use IP geolocation TestingBot's GeoIP feature allows you to test your app from various parts of the world, by using IP addresses in [over 20 different countries](https://testingbot.com/support/web-automate/selenium/test-options#geo). When you enable GeoIP, all traffic from your mobile Android app will originate from a specific IP address hosted in the country that you choose. ## GeoIP example To use GeoIP, you can specify the geoIP option when starting an Espresso test. Please see the example below where we specify that the app should connect via Germany. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --geo-location "DE" The `DE` abbreviation is the ISO code of Germany. You can find other [GeoIP country codes](https://testingbot.com/support/web-automate/selenium/test-options#geo) to use. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "geoLocation": "DE" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" The `DE` abbreviation is the ISO code of Germany. You can find other [GeoIP country codes](https://testingbot.com/support/web-automate/selenium/test-options#geo) to use. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/set-localization-options # Set localization options With TestingBot you can run Android Espresso tests on a localized version of your Android app. You can configure the language, locale and timezone of the remote device before running an Android Espresso test. ## Setting Language for Android Espresso Tests You can test a localized version of your app with Android Espresso, by changing the language of the application under test. You will need to specify a `language` option with the ISO code of the language you want to use. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --language "fr" Use an [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to set the language of your app. Your app needs to be compiled with support for this language to notice a change. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "language": "fr" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Use an [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to set the language of your app. Your app needs to be compiled with support for this language to notice a change. ## Set a locale for Android Espresso Testing It is possible to set a locale, different than the default device's locale, with the `locale` parameter. Please use the CA format (country name abbreviation). For example: `DE` for Germany. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --locale "DE" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "locale": "DE" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## Change timezone for Android Espresso It might be necessary during your tests to change the timezone to a different timezone than the default one on the device (UTC). Please use a timezone format from the [list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --timezone "America/New_York" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "timeZone": "New_York" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/simulate-network-conditions # Simulate Network Conditions TestingBot allows you to test your mobile apps under various network conditions, including download speed, upload speed, packet loss and latency. ## Simulate network conditions using a predefined network profile TestingBot provides a set of predefined network profiles which you can choose from. Profile Name | Bandwidth down/up (kbps) | Packet Loss (%) | Latency (ms) || Edge | 250/150 | 0 | 300 | | 3G | 400/100 | 0 | 100 | | 4G | 18000/9000 | 0 | 100 | | airplane | 0 | 100 | 0 | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --throttle-network "3G" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "throttle_network": "3G" }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" ## Simulate network conditions using a custom network profile You can specify a custom set of parameters, including: - Download rate (kbps) - Upload rate (kbps) - Packet loss (%) - Latency (ms) [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) The CLI supports predefined network profiles. For custom network profiles, use the cURL API directly. # Predefined profiles: 4G, 3G, Edge, airplane testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --platform-version "12" \ --throttle-network "Edge" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/espresso/:id/run" \ -d '{ "espressoOptions": { "throttle_network": { "uploadSpeed": 10240, "downloadSpeed": 10240, "latency": 0, "loss": 0 } }, "capabilities":[{"platform":"ANDROID", "version":12, "deviceName":"Pixel 6", "platformName":"Android"}]}' \ -H "Content-Type: application/json" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/espresso/test-reports # Espresso Test Reports TestingBot currently offers both test reports from inside the TestingBot member dashboard, or through REST-API where you can use a [JUnit formatted XML report](https://testingbot.com#junit). ## Dashboard Report When you run Espresso Tests with TestingBot, you will find the test results, together with a video of the test, in the [TestingBot member dashboard](https://testingbot.com/members). ## API report You can query the TestingBot API to fetch the result of the Espresso test run(s). [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) By default, the CLI waits for test completion and displays results in real-time: testingbot espresso app.apk app-test.apk --device "Pixel 6" The CLI will show: - Upload progress for app and test APK - Device allocation status - Live output from Espresso tests - Final pass/fail status Use `--async` to start tests without waiting for results: testingbot espresso app.apk app-test.apk --device "Pixel 6" --async curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/espresso/:id/:run_id" Replace the `:id` and `:run_id` with the identifiers you received during the app upload call and the run call. You will get back a response similar to this one: {"id":86,"created_at":"2023-11-05T18:45:51.000Z","status":"DONE","capabilities":{"version":"12","deviceName":"Pixel 6","platformName":"Android"},"success":false,"test":{"sessionId":"30f642d082c3-804f3c0ec2df-a18b2d431ffb-169920992163-48455547","environment":{"name":"chrome","os":"Pixel 6 - 12.0","version":"12.0"}},"version":"1.0"} ## JUnit XML report You can query our API to fetch a JUnit XML report which you can use a post-build step in your CI/CD environment. **Report Structure** In the XML report, each session maps to a `testsuite` tag. Inside that tag, multiple `testcase` items are available, each mapping to a single Espresso test. If a test failed, a `failure` or `error` tag will be available. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Download the JUnit XML report after test completion: testingbot espresso app.apk app-test.apk \ --device "Pixel 6" \ --report junit \ --report-output-dir ./reports The schema corresponds to the Android Studio's Gradle schema used when running JUnit tests. curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/espresso/:id/report" The schema corresponds to the Android Studio's Gradle schema used when running JUnit tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help # Mobile App Help Please see the topic below for help with Automated App testing: ## Help Topics - [Prepare your App](https://testingbot.com/support/app-automate/help/prepare) - [Upload your App](https://testingbot.com/support/app-automate/help/upload) - [Tunnel + Real Devices](https://testingbot.com/support/app-automate/help/tunnel) - [FAQ](https://testingbot.com/support/app-automate/help/faq) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/prepare # Prepare your Mobile App for Automated Testing TestingBot provides Android Emulators and iOS Simulators as well as [Real Devices](https://testingbot.com/support/app-automate/devices) to run tests against your mobile app. Below are the steps necessary to prepare your mobile app for Automated Testing. ## Building your app You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: ### For Android: - Please supply the URL to your `.apk` or `.aab` file. **Important:** the .apk file needs to be compiled for the emulator/device you are running your test on (x86 or arm). - Your app needs to have internet permissions - The URL to the `.apk` file must be publicly available, or you can use our [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload) to temporarily host your mobile app. ### For iOS (Real Device): - Please supply the URL to an [.ipa file](https://testingbot.com#ipa). The URL must be publicly available, or you can use our [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload) to temporarily host your mobile app. - By default, we [automatically resign](https://testingbot.com/support/app-automate/help/app-resigning) your [.ipa file](https://testingbot.com#ipa) so that your development builds can run on our devices. If you don't want this, specify `resigningEnabled: false` in your `tb:options` capabilities. - Please make sure your target version matches the version of the simulator you want to test on. ### For iOS (Simulator): - Please supply the URL to a .zip file that contains your .app - The .app needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the .app bundle: zip -r MyApp.zip MyApp.app - Please make sure your target version matches the version of the simulator you want to test on. ## Building IPA file To build an IPA file, please follow these steps: - Open your project in XCode. - Select **Generic iOS Device** as a project device target. - In the **Product** menu, select **Archive**. - Once archived, click **Export**. - You will be asked what kind of export mode you want, you can pick any of these methods: **Ad Hoc** , **Enterprise** or **Development mode**. - When asked for **Distribution options** , please set these options: - App Thinning: disabled - Uncheck **Rebuild from Bitcode** - Uncheck **Strip Swift Symbols** - Uncheck **Include manifest for over-the-air installation** - Select your **Distribution Certificate** and **Provisioning Profile (either Automatic or Manual)**. - Now your `IPA` file should be generated, export it to a folder on your hard disk. - You can now upload the `IPA` file to a public URL or use our [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload) to temporarily host your app. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/upload # Upload your App In order to run tests against your mobile app, our devices need to be able to download your app. There are two ways to configure your tests to do this: - Upload your app to TestingBot Storage: our private upload servers. - Specify an HTTP or HTTPS url to the app you uploaded on a public internet website. ## TestingBot Storage With TestingBot Storage, you can upload your app to our servers. The advantage of this is that your tests will start faster, as the device can download the app from our internal network, instead of the public internet. To get started, simply submit your app to our API: $ curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -F "file=@/path/to/app/file/Application-debug.apk" This call will return a unique identifier for your app (`{"app_url": "tb://..."}`), which you can use in the desired capabilities (see example below). More information regarding this API call and other similar calls (update uploaded file, delete uploaded file, list uploaded files) are available in [our API documentation](https://testingbot.com/support/api#upload). Note: uploads to TestingBot Storage are automatically deleted after 62 days. require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "18.0", "appium:app" => "tb://...", # specify the link to your app here "tb:options" => { "name" => "single_test", "build" => "Ruby Appium Sample" } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver driver.find_element(:name, "inputA").send_keys 5 driver.find_element(:name, "inputB").send_keys 10 driver.quit ## Public Internet If you have your app available on a public website, you can specify this in the desired capabilities: require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "18.0", "appium:app" => "https://...", # specify the link to your app here "tb:options" => { "name" => "single_test", "build" => "Ruby Appium Sample" } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver driver.find_element(:name, "inputA").send_keys 5 driver.find_element(:name, "inputB").send_keys 10 driver.quit Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/tunnel # Using TestingBot Tunnel with Real Devices With TestingBot tunnel, we create a secure connection between a real device running in our datacenter, and your computer and internal network. This way, you can run tests against apps using internal (staging) APIs, from our real mobile devices. Or test websites running on your local network through Safari/Chrome running on a real device. TestingBot Tunnel in combination with Real Devices is available for both **public devices** and **private devices**. More information regarding our TestingBot Tunnel is available on our [TestingBot Tunnel documentation page](https://testingbot.com/support/tunnel). ## Known Limitations - **Localhost testing does not work on iOS**. Due to an iOS Restriction, it is currently not possible to run tests against `http(s)://localhost` with TestingBot Tunnel. A possible workaround would be to change the hosts file on the machine running TestingBot Tunnel, and add a custom hostname (for example `mylocalwebsite` and the IP address `127.0.0.1`). Then configure your tests to use `http(s)://mylocalwebsite/...` instead of localhost. ## Security and Privacy (Advisory) At TestingBot, we clean each device after every test. We take the utmost care to clean as much from the device as we can, to make sure your test runs without any leftover artifacts from previous tests. However, due to the complexity of automatically cleaning different mobile device models, we cannot 100% guarantee that all data generated from a previous session is removed from our **public devices**. Using our TestingBot tunnel in combination with a public device might have potential security risks. We recommend to [opt for private, dedicated devices](https://testingbot.com/enterprise/private-device-cloud) for maximum security. With **private devices** , your company will be the only one running tests on the device. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/faq # Mobile App Testing FAQ TestingBot provides mobile application testing on both **virtual devices** as well as **physical devices**. Virtual devices are Android emulators and iOS simulators. TestingBot provides a large collection of these, available for mobile app testing, both automated and manual testing. This FAQ document will list questions and answers regarding the mobile native app testing service. ## Can I run Android emulator tests using Espresso instead of Appium? TestingBot allows you to upload native mobile Android apps and use [Espresso testing](https://testingbot.com/support/app-automate/espresso) on both Android emulators and physical devices. Of course, you can do [Appium automated app testing](https://testingbot.com/support/app-automate/appium) as well on TestingBot. ## Which apps are available on the devices? TestingBot uses stock images for Android emulators, which come equipped with the PlayStore and Chrome. Similarly, we use stock iOS simulators which come with Safari by default. TestingBot does not use jailbroken or rooted physical devices. All Android devices come with factory settings, with PlayStore enabled (if available) and Chrome. The iOS devices come with Safari, the Safari version depends on the iOS version installed on the device. ## How does manual testing work? We provide access to a realtime view of an Android emulator, iOS simulator, Android physical device and iOS device. You can interact with the device, from your own mouse and keyboard, without installing any plugins or software. The screens are streamed either through WebRTC or VNC, depending on your network connectivity settings. ## When are new devices added? Our public device pool contains a collection of the most popular devices used, backed by public statistics of mobile device usage. When new devices are released to the public, we aim to procure, setup and make these available to our customers in less than 2 weeks. The criteria we use for selecting which devices to add depends on the popularity of the device and the demand for testing on such a device. If you are looking to test on a specific device, please do not hesitate to [reach out to us](https://testingbot.com/contact/new). ## Is it possible to test push notifications? It is possible to test push notifications in the following scenarios: - **Android Physical Devices** It will work automatically. Simply install the app and allow push notifications. - **iOS Physical Devices** This is only possible for private devices, which require an [Enterprise plan](https://testingbot.com/enterprise). [Reach out to us](https://testingbot.com/contact/new) for more information. - **Android Emulators** Unfortunately this is not supported yet. If you'd like to be a part of the beta program, please let us know. - **iOS Simulators** This is possible since Appium 1.21.0. ## Can I upload or download files from a device or sim/emu? Yes, you can upload files to devices using Appium's `pushFile` command and download files using the `pullFile` command. Please see our [Upload Files documentation](https://testingbot.com/support/app-automate/appium/upload-files) for more information. ## How is my app protected during mobile app testing? Our Real Device Cloud is located in a secure datacenter in Europe. We make sure that every device is fully protected, both physically and digitally. All traffic happens through SSL and each device is cleaned after usage: - All user apps are removed - Generated data, such as browser data, is wiped - SD card, accounts, and other data that was altered is removed TestingBot's [automated cleaning process](https://testingbot.com/support/app-automate/help/cleaning) makes sure that no data is available from an earlier test. If you think this did happen, please reach out to us so we can reset the device and check why this happened. ## Is audio supported, or microphone access? Audio is available for Android devices running Android 12 and higher. Older physical devices do not have the capability to stream audio, these will only stream a realtime video of the screen. ## My app needs to make requests to internal services. Can I use a VPN for this? We suggest using the [TestingBot Tunnel](https://testingbot.com/support/tunnel). It will set up the device or sim/emu to proxy all requests through the tunnel to your internal services. An alternative solution is to [whitelist our IP addresses](https://testingbot.com/support/other/configuration#ip-range), which would allow our devices to reach your protected services. ## Can I use Bluetooth on the physical devices? Yes you can, please [reach out](https://testingbot.com/contact/new) to discuss your specific use case. ## Can I trigger a disconnect or reconnect from a charging cable? This is currently not supported. ## Can I change the orientation of the device? Yes, both on simulators/emulators as well as on physical devices. You can change the orientation to either `PORTRAIT` or `LANDSCAPE`. You can do this via our manual testing feature, or [change the screen orientation during an automated test](https://testingbot.com/support/app-automate/appium/screen-orientation). ## Are code coverage reports by JaCoCo supported? We currently do not support this. ## Can I change the geolocation during my test? Yes, you can [change the geolocation](https://testingbot.com/support/web-automate/selenium/test-options#geo) either during manual testing or via automated tests. ## Why do I sometimes see a lock/PIN screen? On trial devices, in our public device pool, we need to make some areas password protected to prevent users from changing certain settings. The password protection is not in place on non-trial devices. ## Can I test payments on the physical devices? Payments can be tested on private devices only. Please [reach out to us](https://testingbot.com/contact/new) for more information. ## Can I inspect the mobile app in your manual testing feature? Yes, you can inspect the mobile app from the manual testing feature. Simply open the **DevTools** option and click the **Inspector** tab. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/cleaning # Real Device Cleaning Process TestingBot automatically cleans each physical mobile device after every test session. We do this to ensure each new test starts with a clean state, without any leftover data from previous sessions. The cleaning process we use is automated for both iOS and Android. For devices in the public device pool, each test session automatically ends with a thorough cleaning process where we delete any apps installed by the user, together with various other files and data that were generated. If you are using a private device, there's the possibility to alter or completely disable the cleaning process. You would for example use this when you want to make sure that a specific state is kept between various test sessions. ## Cleaning Process TestingBot uses a proprietary process to clean its devices. Below are the various processes that happen when a device is being cleaned. - All apps that have been installed by the customer are deleted. Some applications, which are used by TestingBot to operate the device, are kept. - The browser history, together with any cached website data and cookies are removed. - AppleID sessions are removed. - Network settings such as WiFi and DNS configurations are reset to their default state. - The system locale, language and time zone are reset to their default. (English, UTC+2). - Any mock GPS location is reset to Brussels, Belgium. - Media files such as Photos, Videos and other Files are removed from the device. TestingBot's cleaning process aims to clean as much as possible from the device. If you prefer the guarantee of a pristine device, please consider using a [private mobile device](https://testingbot.com/enterprise/private-device-cloud). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/help/app-resigning # iOS App Resigning When you [upload an iOS app](https://testingbot.com/support/app-automate/help/upload) to TestingBot, we will automatically re-sign the `.ipa` file with our own provisioning profile, to be able to install and run your app on our mobile devices. Because of this procedure, the [entitlements](https://developer.apple.com/documentation/bundleresources/entitlements) of your iOS app will be removed. You can choose to disable this re-signing, if your app is signed using the [Apple Developer Enterprise Program](https://developer.apple.com/programs/enterprise/). This way you can test **push notifications** or [universal links](https://developer.apple.com/ios/universal-links/) on our physical devices. ## Disable iOS Resigning [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) capabilities = { "tb:options" => { "resigningEnabled" => false } } Map tbOptions = new HashMap<>(); tbOptions.put("resigningEnabled", false); options.setCapability("tb:options", tbOptions); $capabilities = [ "tb:options" => [ "resigningEnabled" => false ] ]; capabilities = { "tb:options": { "resigningEnabled": False } } const capabilities = { "tb:options": { "resigningEnabled": false } }; var tbOptions = new Dictionary { ["resigningEnabled"] = false }; options.AddAdditionalAppiumOption("tb:options", tbOptions); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/smart-tv # Smart TV Testing Run tests on physical Smart TV devices with TestingBot, using the open-source test framework Appium. Currently TestingBot supports running automated tests on physical AppleTV 4k devices. To get started with testing your Smart TV app in the cloud, you will need to follow these steps: - Upload your native Smart TV app, either to a public URL or using TestingBot Storage. - Create an Appium test script that will connect to TestingBot. - The results will be available in the TestingBot dashboard, together with a video of the test and logs. ## Upload Smart TV App To run Smart TV tests on TestingBot, you will first have to upload your `.ipa` file to TestingBot Storage. [cURL](https://testingbot.com#) $ curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -F "file=@/path/to/app/file/tvos.ipa" This call will return a unique identifier for your SmartTV app (`{"app_url": "tb://..."}`), which you can use in the capabilities in your test (see example below). More information regarding this API call and other similar calls (update uploaded file, delete uploaded file, list uploaded files) are available in [the TestingBot API documentation](https://testingbot.com/support/api#upload). Note: uploads to TestingBot Storage are automatically deleted after 62 days. ## Run your first SmartTV test Once you've [uploaded your Smart TV app](https://testingbot.com#upload), you can start with running your first test on the TestingBot SmartTV cloud. TestingBot currently only supports running tests on physical AppleTV 4k devices. Please see the example tests below, where we use the [TestingBot tvOS example app](https://github.com/testingbot/tvos-example) to input two numbers in the calculator and verify its sum. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'appium_lib' caps = {} caps['name'] = 'Ruby tvOS Example' caps['deviceName'] = 'Apple TV 4K' caps['platformName'] = 'tvOS' caps['version'] = '17.4' caps['app'] = 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa' caps['realDevice'] = true appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://key:secret@hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) wait.until { driver.find_element(:accessibility_id, "inputField1").displayed? } inputField1 = driver.find_element(:accessibility_id, "inputField1") inputField1.click inputField1.send_keys 5 driver.execute_script('mobile: pressButton', { name: 'down' }) driver.execute_script('mobile: pressButton', { name: 'select' }) driver.switch_to.active_element.send_keys 10 driver.execute_script('mobile: pressButton', { name: 'down' }) driver.execute_script('mobile: pressButton', { name: 'select' }) result = driver.find_element(:accessibility_id, "resultField") if (!result.nil?) && (result.text.to_i == 15) puts "Test Passed" else puts "Test Failed" end driver.quit const wdio = require('webdriverio'); const caps = { name: 'Node.js tvOS Example', deviceName: 'Apple TV 4K', platformName: 'tvOS', platformVersion: '17.4', app: 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', realDevice: true }; const options = { protocol: 'https', hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', user: 'key', // Replace 'key' with your TestingBot key key: 'secret', // Replace 'secret' with your TestingBot secret capabilities: caps }; (async () => { // Start the Appium driver const driver = await wdio.remote(options); try { // Wait for the first input field to be displayed const inputField1 = await driver.$('~inputField1'); await inputField1.waitForDisplayed({ timeout: 30000 }); // Interact with the first input field await inputField1.click(); await inputField1.setValue(5); // Navigate down and select await driver.execute('mobile: pressButton', { name: 'down' }); await driver.execute('mobile: pressButton', { name: 'select' }); // Send keys to the active element await driver.switchToParentFrame(); // Ensure focus is on the active frame await driver.activeElement().setValue(10); // Navigate down and select the result await driver.execute('mobile: pressButton', { name: 'down' }); await driver.execute('mobile: pressButton', { name: 'select' }); // Verify the result const result = await driver.$('~resultField'); const resultText = await result.getText(); if (resultText && parseInt(resultText, 10) === 15) { console.log('Test Passed'); } else { console.log('Test Failed'); } } catch (err) { console.error('Error occurred:', err); } finally { // Quit the driver await driver.deleteSession(); } })(); from appium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # Define capabilities caps = { "name": "Python tvOS Example", "deviceName": "Apple TV 4K", "platformName": "tvOS", "platformVersion": "17.4", "app": "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", "realDevice": True } # Appium server URL server_url = "https://key:secret@hub.testingbot.com/wd/hub" # Initialize the driver driver = webdriver.Remote(server_url, caps) try: # Wait for the first input field to be displayed wait = WebDriverWait(driver, 30) input_field1 = wait.until(EC.presence_of_element_located((By.ACCESSIBILITY_ID, "inputField1"))) # Interact with the first input field input_field1.click() input_field1.send_keys("5") # Navigate down and select the second input field driver.execute_script('mobile: pressButton', {'name': 'down'}) driver.execute_script('mobile: pressButton', {'name': 'select'}) # Send keys to the active element (second input field) driver.switch_to.active_element.send_keys("10") # Navigate down and select the result field driver.execute_script('mobile: pressButton', {'name': 'down'}) driver.execute_script('mobile: pressButton', {'name': 'select'}) # Verify the result result_field = driver.find_element(By.ACCESSIBILITY_ID, "resultField") result_text = result_field.text if result_text and int(result_text) == 15: print("Test Passed") else: print("Test Failed") except Exception as e: print(f"An error occurred: {e}") finally: # Quit the driver driver.quit() import io.appium.java_client.AppiumDriver; import io.appium.java_client.MobileBy; import io.appium.java_client.remote.MobileCapabilityType; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; import java.time.Duration; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class TvOSTest { public static void main(String[] args) { AppiumDriver driver = null; try { // Set capabilities DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("name", "Java tvOS Example"); caps.setCapability("deviceName", "Apple TV 4K"); caps.setCapability("platformName", "tvOS"); caps.setCapability("platformVersion", "17.4"); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); caps.setCapability("realDevice", true); URL serverUrl = new URL("https://key:secret@hub.testingbot.com/wd/hub"); driver = new AppiumDriver<>(serverUrl, caps); // Wait for the first input field to be displayed WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); WebElement inputField1 = wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.AccessibilityId("inputField1"))); inputField1.click(); inputField1.sendKeys("5"); // Navigate down and select the second input field driver.executeScript("mobile: pressButton", Map.of("name", "down")); driver.executeScript("mobile: pressButton", Map.of("name", "select")); // Send keys to the active element (second input field) WebElement activeElement = driver.switchTo().activeElement(); activeElement.sendKeys("10"); // Navigate down and select the result field driver.executeScript("mobile: pressButton", Map.of("name", "down")); driver.executeScript("mobile: pressButton", Map.of("name", "select")); WebElement resultField = driver.findElement(MobileBy.AccessibilityId("resultField")); String resultText = resultField.getText(); if (resultText != null && Integer.parseInt(resultText) == 15) { System.out.println("Test Passed"); } else { System.out.println("Test Failed"); } } catch (Exception e) { e.printStackTrace(); } finally { // Quit the driver if (driver != null) { driver.quit(); } } } } using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Enums; using OpenQA.Selenium.Appium.iOS; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; class TvOSTest { static void Main(string[] args) { AppiumDriver driver = null; try { // Set capabilities var caps = new AppiumOptions(); caps.AddAdditionalCapability(MobileCapabilityType.PlatformName, "tvOS"); caps.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Apple TV 4K"); caps.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "17.4"); caps.AddAdditionalCapability(MobileCapabilityType.App, "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); caps.AddAdditionalCapability("realDevice", true); caps.AddAdditionalCapability("name", "C# tvOS Example"); // Initialize driver var serverUri = new Uri("https://key:secret@hub.testingbot.com/wd/hub"); driver = new IOSDriver(serverUri, caps); // Wait for the first input field to be displayed var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30)); var inputField1 = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputField1"))); // Interact with the first input field inputField1.Click(); inputField1.SendKeys("5"); // Navigate down and select the second input field driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "down" } }); driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "select" } }); // Send keys to the active element (second input field) var activeElement = driver.SwitchTo().ActiveElement(); activeElement.SendKeys("10"); // Navigate down and select the result field driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "down" } }); driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "select" } }); // Verify the result var resultField = driver.FindElement(MobileBy.AccessibilityId("resultField")); var resultText = resultField.Text; if (!string.IsNullOrEmpty(resultText) && int.Parse(resultText) == 15) { Console.WriteLine("Test Passed"); } else { Console.WriteLine("Test Failed"); } } catch (Exception ex) { Console.WriteLine($"An error occurred: {ex.Message}"); } finally { // Quit the driver driver?.Quit(); } } } ## View SmartTV Test Results Once your test has finished running, you will see a new test entry in the [TestingBot dashboard.](https://testingbot.com/members). If you click the test, you will see detailed information about the test, including a video recording of the test, logs and screenshots. You can also use the [TestingBot API](https://testingbot.com/support/api) to programmatically fetch the test results. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/smart-tv/options # Smart TV Test Options Please see the examples below on how to customize your test run on the available Smart TV devices. ## Specifying Appium Version TestingBot will use the most recent, compatible, Appium version according to the device, OS and version you specify. If you'd like to specify your own Appium version, you can do this with the `appiumVersion` capability. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", deviceName: "Apple TV 4K", browserVersion: "17.4", app: 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "tb:options" => { "appiumVersion" : "2.0" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("appiumVersion", "2.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("deviceName", "Apple TV 4K"); caps.setCapability("browserVersion", "17.4"); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); tbOptions = { 'name': 'W3C Sample', 'appiumVersion': "2.0" } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'browserVersion': "17.4", 'deviceName': "Apple TV 4K", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "deviceName": 'Apple TV 4K', "version": '17.4', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "appiumVersion": "2.0" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "17.4", PlatformName = "tvOS", DeviceName = "Apple TV 4K", App = "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["appiumVersion"] = "2.0" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Appium 2 Versions We currently support these Appium 2 versions: - 2.11.3 - 2.10.3 - 2.9.0 - 2.5.1 - 2.4.1 - 2.3.0 - 2.2.1 If you specify `"appiumVersion": "latest"`, TestingBot will automatically use the latest Appium version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions of Appium. ### Geolocation Testing TestingBot provides an option where you can specify from which country you'd like to run the test from. We will configure the Smart TV device to use a proxy that will route all traffic through the specified country. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", deviceName: "Apple TV 4K", version: "17.4", "tb:options" => { "testingbot.geoCountryCode" : "DE" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("testingbot.geoCountryCode", "DE"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); tbOptions = { 'testingbot.geoCountryCode': "DE" } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "testingbot.geoCountryCode": "DE" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["testingbot.geoCountryCode"] = "DE" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Specify `testingbot.geoCountryCode` with one of the following country codes: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States **Important:** this does not work on tvOS 4.4 ### Change Test Name Add a name to this test, which will show up in the TestingBot member area and API. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "name" : "My Test Name" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("name", "My Test Name"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'name' => "My Test Name" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': "My Test Name" } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'deviceName': "Apple TV 4K", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "name": "My Test Name" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "My Test Name" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || string | unnamed test | ### Group Tests A key you can use to group certain tests in the same build (for example in Jenkins). The builds will appear in our member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "build" : "My First Build" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("build", "My First Build"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'build' => "My First Build" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'build': "My First Build" } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'deviceName': "Apple TV 4K", 'version': '17.4', 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "build": "My First Build" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["build"] = "My First Build" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type || string | ### Idle Timeout The maximum amount of time a device will wait before proceeding to the next step in your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "idletimeout" : 130 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("idletimeout", 130); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'idletimeout' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'idletimeout': 130 } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "idletimeout": 130 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["idletimeout"] = 130 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || int (specify number of seconds) | 130 seconds | ### Maximum Test Duration The maximum duration for a single test. This is a safeguard to prevent bad tests from using up your credits. We generally recommend to keep tests short (less than 10 minutes). It's better to split up large tests in smaller individual tests. This keeps your tests fast and allows for more parallelization of your tests. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "maxduration" : 1800 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("maxduration", 1800); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'maxduration' => 1800 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'maxduration': 1800 } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "maxduration": 1800 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["maxduration"] = 1800 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || int (specify number of seconds) | 1800 seconds (30 minutes) | ### Custom Metadata Send along custom data, for example your release, server, commit hash, ... This will show up on the test detail page in the TestingBot member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "extra" : "Extra Information" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("extra", "Extra Information"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'extra' => "Extra Information" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'extra': "Extra Information" } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "extra": "Extra Information" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["extra"] = "Extra Information" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type || string | ### Taking screenshots during your tests By default, TestingBot does not capture screenshots at every step of your mobile test. If you wish to take a screenshot for every step, please add this capability (set to `true`) to your request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { screenshot: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenshot", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'screenshot' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenshot': True } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa, 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenshot": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "23", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenshot"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | false | ### Make a video of your tests By default we record a video of your test, which is accessible in the member area. If you do not wish to have this, you can disable it with this option. Video should not slow down your test considerably. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", "tb:options" => { screenrecorder: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenrecorder", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'screenrecorder' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenrecorder': True } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenrecorder": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenrecorder"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | true | ### Test Privacy Make the test results for this test public so that everyone can access the results. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", "tb:options" => { "public" : false } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("public", false); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'public' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'public': False } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "public": false } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["public"] = false }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | false | ### Customize Logging By default, TestingBot records logs of all test actions and its drivers. Set this option to `false` if you don't want TestingBot to record anything (for example, if you have sensitive data). You will not see any test logs in our member dashboard. Set to `strip-parameters` to prevent the POST/GET parameters from being logged on the TestingBot test detail page (does not affect other logs like Appium logs, Chromedriver logs, ...). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "tvOS", app: "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", version: "17.4", deviceName: "Apple TV 4K", "tb:options" => { "recordLogs" : true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("recordLogs", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "tvOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('tvOS'); $capabilities->setCapability('tb:options', array( 'recordLogs' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'recordLogs': True } chromeOpts = { 'app': "https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa", 'platformName': "tvOS", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://github.com/testingbot/tvos-example/releases/download/1.0.0/tvos-example.ipa', "platformName": 'tvOS', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "recordLogs": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "17.4", PlatformName = "tvOS", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["recordLogs"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value | Possible Values: || string | "true" | `true`, `false`, or `strip-parameters` | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/smart-tv/remote-control-navigation # TvOS (Apple TV 4K) During an Appium test you can use the buttons actions to simulate remote control navigation on the Apple TV. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script('mobile: pressButton', { name: 'down' }) driver.execute_script('mobile: pressButton', { name: 'select' }) await driver.execute('mobile: pressButton', { name: 'down' }); await driver.execute('mobile: pressButton', { name: 'select' }); driver.execute_script('mobile: pressButton', {'name': 'down'}) driver.execute_script('mobile: pressButton', {'name': 'select'}) driver.executeScript("mobile: pressButton", Map.of("name", "down")); driver.executeScript("mobile: pressButton", Map.of("name", "select")); driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "down" } }); driver.ExecuteScript("mobile: pressButton", new Dictionary { { "name", "select" } }); The following buttons are available: | Button Name | Behaviour | | --- | --- | | Home | Return to the home screen. | | Menu | Return to the previous operation or screen. In the context of tvOS, it works as a traditional back button. | | Select | Select the item with the current focus. | | Up | Move the focus upward in the UI. | | Down | Move the focus downward in the UI. | | Left | Move the focus left in the UI. | | Right | Move the focus right in the UI. | | Play/Pause | Control media playback. Play/Pause is a toggle. | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium # Your first test with Appium Appium allows you to run Automated tests against hybrid and native mobile apps, on iOS and Android devices. Simply upload your mobile app and run it on iOS and Android devices in the TestingBot cloud. ## Automated Mobile App Testing To get started, please choose a programming language/framework: ### [Java](https://testingbot.com/support/app-automate/appium/java) Get started with Java mobile app testing using Appium. - [Java](https://testingbot.com/support/app-automate/appium/java) - [TestNG](https://testingbot.com/support/app-automate/appium/java/testng) ### [NodeJS](https://testingbot.com/support/app-automate/appium/nodejs) Get started with NodeJS mobile app testing using Appium. - [NodeJS](https://testingbot.com/support/app-automate/appium/nodejs) - [CodeceptJS](https://testingbot.com/support/app-automate/appium/nodejs/codeceptjs) - [WebDriverIO](https://testingbot.com/support/app-automate/appium/nodejs/webdriverio) ### [C#](https://testingbot.com/support/app-automate/appium/csharp) Get started with C# mobile app testing using Appium. - [C#](https://testingbot.com/support/app-automate/appium/csharp) - [NUnit](https://testingbot.com/support/app-automate/appium/csharp/nunit) - [SpecFlow](https://testingbot.com/support/app-automate/appium/csharp/specflow) ### [Python](https://testingbot.com/support/app-automate/appium/python) Get started with Python mobile app testing using Appium. - [Python](https://testingbot.com/support/app-automate/appium/python) ### [PHP](https://testingbot.com/support/app-automate/appium/php) Get started with PHP mobile app testing using Appium. - [PHP](https://testingbot.com/support/app-automate/appium/php) ### [Ruby](https://testingbot.com/support/app-automate/appium/ruby) Get started with Ruby mobile app testing using Appium. - [Ruby](https://testingbot.com/support/app-automate/appium/ruby) ## Preparing your App Please see our [Prepare Mobile App](https://testingbot.com/support/app-automate/help/prepare) documentation to make sure your app will work on our emulators/devices. ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appium:appActivity** and **appium:appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **appium:chromeOptions** : additional chromedriver options you can supply. - **appium:otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **appium:locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **appium:newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/capabilities # Appium Capabilities Generator Generate Appium capabilities for your mobile automated tests. Choose your device, OS version and configuration options to get the exact code you need for Java, Python, NodeJS, C#, Ruby or PHP. [![Selenium capabilities](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)Selenium](https://testingbot.com/support/web-automate/selenium/capabilities)[![Appium capabilities](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium/capabilities)[![Puppeteer capabilities](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer/capabilities)[![Playwright capabilities](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)Playwright](https://testingbot.com/support/web-automate/playwright/capabilities) Mobile Environment ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available devices and platforms. App URL or ID Appium Version3.0.12.11.52.10.32.9.02.8.12.7.02.6.02.5.42.4.12.3.02.2.32.1.32.0.11.22.31.22.21.22.11.22.01.21.01.20.21.19.11.18.31.17.11.16.01.15.1 ## Project Capabilities Test NameAllows you to customize the name of the test, as it will appear in the dashboard. Build NameGroup tests under the same build identifier for easy retrieval. ## Debugging Record Video YesNo Take Screenshot After Each Step YesNo Collect Logs YesNo ## Customization Locale Geolocation TestingRun the test from a different geographical location.NoneRandom CountryAustraliaBahrainBelgiumBrazilCanadaChileFranceGermanyIndiaItalyJapanNorwaySingaporeSouth AfricaSwedenSwitzerlandUnited Arab EmiratesUnited KingdomUnited States Screen OrientationPortraitLandscape Looking for more options? See [all Appium capabilities](https://testingbot.com/support/app-automate/appium/options). W3C Protocol W3C is the newest WebDriver protocol, TestingBot recommends using W3C. JSONWP JSONWP is the legacy protocol which is no longer actively maintained. JavaPythonNodeJSC#RubyPHP MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, "safari"); capabilities.setCapability(CapabilityType.BROWSER_VERSION, "18.6"); capabilities.setCapability("appium:deviceName", "iPhone 16"); capabilities.setCapability(CapabilityType.PLATFORM_NAME, "iOS");` --- URL: https://testingbot.com/support/app-automate/appium/appium-versions # Appium 3 TestingBot supports Appium 3. See [Specify Appium version](https://testingbot.com#versions) to use Appium 3 with your tests. Appium 3 introduces a couple of breaking changes compared to Appium 2. The main changes are removal of legacy code and protocols, which were already marked as deprecated in [Appium 2](https://testingbot.com#appium2). Below is a list of breaking changes in Appium 3: - Node.js / NPM minimum version bump (to 20.19 / 10) - which is handled by TestingBot. - Removal of certain deprecated endpoints - Security feature flag prefix requirements (for example replacing `adb_shell` with `uiautomator2:adb_shell`). Please see the [Appium 3 migration guide](https://appium.io/docs/en/latest/guides/migrating-2-to-3/) for more details. ## Appium 2 Appium 2 is the new version of Appium, the mobile automation framework to run tests against websites and mobile apps on phones and tablets (both simulators/emulators and physical devices). The main difference between Appium 2 and Appium 1 is that Appium 2 uses the concept of plugins and drivers. This makes for a better ecosystem, with cleaner code and improved flexibility and performance. The drivers will add support for any given platform, for example an xcuitest driver will provide support for iOS XCUITest automation, an espresso driver for Android Espresso. Plugins allow for adding and customizing existing behavior of Appium. Drivers and plugins can be easily shared, installed or removed from Appium 2. Appium 2 supports iOS 14 and above and Android 6 and above. ## Appium Versions TestingBot currently supports these Appium versions: Appium Version | EOL Date | Description || 3.0.1 | active | These drivers are installed: - `appium-xcuitest-driver`: 10.0.2 - `appium-safari-driver`: 4.0.1 - `appium-uiautomator2-driver`: 5.0.0 - `appium-flutter-driver`: 2.14.2 | | 2.17.0 or `latest` | active | These drivers are installed: - `appium-xcuitest-driver`: 8.4.3 - `appium-safari-driver`: 3.5.23 - `appium-uiautomator2-driver`: 4.1.2 - `appium-flutter-driver`: 2.14.2 - `appium-flutter-integration-driver`: 1.1.3 | | 2.11.3 | active | These drivers are installed: - `appium-xcuitest-driver`: 7.24.16 - `appium-safari-driver`: 3.5.17 - `appium-uiautomator2-driver`: 3.7.7 - `appium-flutter-driver`: 2.9.2 - `appium-flutter-integration-driver`: 1.1.3 | | 2.10.3 or `latest-1` | December 1, 2025 | These drivers are installed: - `appium-xcuitest-driver`: 7.17.5 - `appium-uiautomator2-driver`: 3.5.4 - `appium-flutter-driver`: 2.6.0 | | 2.9.0 | November 1, 2025 | These drivers are installed: - `appium-xcuitest-driver`: 7.17.5 - `appium-uiautomator2-driver`: 3.5.4 - `appium-flutter-driver`: 2.6.0 | | 2.5.1 | October 1, 2025 | These drivers are installed: - `appium-xcuitest-driver`: 7.9.1 - `appium-uiautomator2-driver`: 3.0.4 - `appium-flutter-driver`: 2.5.1 | | 2.4.1 | September 1, 2025 | These drivers are installed: - `appium-xcuitest-driver`: 5.15.1 - `appium-uiautomator2-driver`: 2.43.4 - `appium-flutter-driver`: 2.4.1 | If you specify `"appiumVersion": "latest"`, TestingBot will automatically use the latest Appium version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions of Appium. ## Appium 1 Legacy version TestingBot currently supports Appium 1 with its latest version: `1.22.3`. ## Appium 2 example on TestingBot Appium 1 and 2 are both supported on TestingBot, on all our physical devices and virtual devices: iOS simulators and Android emulators. These Appium 2 drivers are installed on TestingBot: - [appium-uiautomator2-driver](https://github.com/appium/appium-uiautomator2-driver) - [appium-xcuitest-driver](https://github.com/appium/appium-xcuitest-driver) - [appium-geckodriver](https://github.com/appium/appium-geckodriver) - [appium-safari-driver](https://github.com/appium/appium-safari-driver) - [Flutter](https://testingbot.com/support/app-automate/appium/flutter) These Appium 2 plugins are pre-installed and can be activated by specifying a `tb:appiumPlugins` capability (by default empty): { 'tb:appiumPlugins': ['images', 'execute-driver', 'universal-xml'] } - [Images Plugin](https://github.com/appium/appium/tree/master/packages/images-plugin) - [Execute Driver Plugin](https://github.com/appium/appium/tree/master/packages/execute-driver-plugin) - [Universal XML Plugin](https://github.com/appium/appium/tree/master/packages/universal-xml-plugin) By default, TestingBot will use Appium 1 for all mobile tests. You can change this by [specifying an Appium Version](https://testingbot.com/support/app-automate/appium/options#appiumVersion). The example below will connect to the TestingBot device grid and will use Appium 2 to run a mobile automation test. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) XCUITestOptions options = new XCUITestOptions(); options.setPlatformName("iOS"); options.setCapability("appium:platformVersion", "18.0"); options.setCapability("appium:deviceName", "iPhone 16"); HashMap tbOptions = new HashMap<>(); tbOptions.put("appiumVersion", "2.5.1"); options.setCapability("tb:options", tbOptions); const capabilities = { platformName: 'iOS', 'appium:platformVersion': '18.0', 'appium:deviceName': 'iPhone 16', 'appium:automationName': 'XCUITest', 'tb:options': { appiumVersion: '2.5.1' } } capabilities = { "platformName" : "iOS", "appium:platformVersion" : "18.0", "appium:deviceName" : "iPhone 16", "appium:automationName": "XCUITest", "tb:options" : { "appiumVersion" : "2.5.1" } } capabilities = { "platformName" => "iOS", "appium:platformVersion" => "18.0", "appium:deviceName" => "iPhone 16", "appium:automationName" => "XCUITest", "tb:options" => { "appiumVersion" => "2.5.1" } } AppiumOptions options = new AppiumOptions(); options.PlatformName = "iOS"; options.AddAdditionalAppiumOption("appium:platformVersion", "18.0"); options.AddAdditionalAppiumOption("appium:deviceName", "iPhone 16"); options.AddAdditionalAppiumOption("appium:automationName", "XCUITest"); var tbOptions = new Dictionary(); tbOptions.Add("appiumVersion", "2.5.1"); options.AddAdditionalAppiumOption("tb:options", tbOptions); ## Appium 2 Changes If you've been using Appium 1 and want to try out Appium 2, then please be aware of the possible breaking changes listed below. ### Protocol Changes Appium 2 only allows the [W3C WebDriver Protocol](https://www.w3.org/TR/webdriver/). Even though Appium 1 has supported this protocol since recent years, it also supported JSONWP (JSON Wire Protocol) and MJSONWP (Mobile Json Wire Protocol). This means that if you are using an older Appium client or binding, you might have trouble communicating with Appium 2. Instead of using `desiredCapabilities`, you now need to use `capabilities` with either `alwaysMatch` or `firstMatch` properties. ### Capabilities Appium only accepts a couple of [standard W3C capabilities](https://www.w3.org/TR/webdriver/#capabilities), including: - `browserName` - `browserVersion` - `platformName` All other capabilities, such as `app` or `deviceName` need to be vendor-prefixed. A vendor prefix means you prefix each key with a string followed by a colon. In Appium's case, this would be `appium:` An example of some of the capabilities you can use with Appium 2: - `appium:app` - `appium:deviceName` - `appium:noReset` ### automationName is required With Appium 2, you now need to specify an automationName. Before, with Appium 1 this was filled in automatically if you did not specify it. For iOS testing, you should use `appium:automationName` with `XCUITest`. For Android, you should set the `appium:automationName` capability to `UiAutomator2`. ### TestingBot specific capabilities You can specify [TestingBot specific capabilities](https://testingbot.com/support/app-automate/appium/options) with the `tb:options` capability. See below for an example where we will be using both Appium 2 and custom TestingBot capabilities. XCUITestOptions options = new XCUITestOptions(); options.setPlatformName("iOS"); options.setCapability("appium:platformVersion", "18.0"); options.setCapability("appium:deviceName", "iPhone 16"); HashMap tbOptions = new HashMap<>(); tbOptions.put("appiumVersion", "2.5.1"); options.setCapability("tb:options", tbOptions); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/csharp ### C# Examples: - [NUnit](https://testingbot.com/support/app-automate/appium/csharp/nunit) - [SpecFlow](https://testingbot.com/support/app-automate/appium/csharp/specflow) # C# Automated App Testing This guide will help you run mobile automated tests with Appium and C# on the TestingBot device cloud. [Command Line](https://testingbot.com#)[Visual Studio](https://testingbot.com#) TestingBot has created a sample Visual Studio project to help you get started with C# and Appium testing. [Download ZIP](https://github.com/testingbot/csharp-app-example/archive/refs/heads/main.zip) You can import this project into Visual Studio and run the tests directly. To run your tests with C# and .NET, you need to have the [.NET SDK](https://dotnet.microsoft.com/download) installed on your machine. - **On Windows:** - Download the [.NET SDK](https://dotnet.microsoft.com/en-us/download) installer and run it. - Or use the `winget` command: `winget install Microsoft.DotNet.SDK.9` - **On MacOS:** `brew install dotnet` - **On Linux:** `sudo apt-get install dotnet-sdk-9.0` After installing the .NET SDK, you can create a new NUnit test project using the command line: dotnet new nunit -n AppiumTest cd AppiumTest Next, add the Appium and Selenium WebDriver packages to your project: dotnet add package Appium.WebDriver dotnet add package Selenium.WebDriver dotnet add package Selenium.Support Replace the contents of `UnitTest1.cs` with the example code below, then run your tests with: TB_KEY=... TB_SECRET=... dotnet test ## Installation See our [C# App example repository](https://github.com/testingbot/csharp-app-example) for a simple example on how to run C# tests on Mobile Devices with TestingBot. Please download the [appium-dotnet-driver](https://github.com/appium/appium-dotnet-driver) and add it to your project. You can use NuGet packages as well, in which case you'll need to install these packages: - Appium.WebDriver - DotNetSeleniumExtras.WaitHelpers - Selenium.WebDriver ## Real Device Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; namespace AppiumNunit { [TestFixture] public class AndroidRealDeviceTest { private AndroidDriver? Driver; [Test] public void SampleTest() { var options = new AppiumOptions { PlatformName = "Android", DeviceName = "Galaxy S10", PlatformVersion = "10.0", App = "https://testingbot.com/appium/sample.apk" }; options.AddAdditionalAppiumOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name, ["realDevice"] = true }); Driver = new AndroidDriver(new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(120)); var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); var inputA = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputA"))); inputA.SendKeys("10"); var inputB = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputB"))); inputB.SendKeys("5"); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.iOS; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; namespace AppiumNunit { [TestFixture] public class iOSRealDeviceTest { private IOSDriver? Driver; [Test] public void SampleTest() { var options = new AppiumOptions { PlatformName = "iOS", DeviceName = "iPhone 15", PlatformVersion = "17.4", App = "https://testingbot.com/appium/sample.ipa" }; options.AddAdditionalAppiumOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name, ["realDevice"] = true }); Driver = new IOSDriver(new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(300)); var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); var inputA = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputA"))); inputA.SendKeys("10"); var inputB = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputB"))); inputB.SendKeys("5"); var sum = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("sum"))); Console.WriteLine(sum.Text); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } ## Simulator/Emulator Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; namespace AppiumNunit { [TestFixture] public class AndroidEmulatorTest { private AndroidDriver? Driver; [Test] public void SampleTest() { var options = new AppiumOptions { PlatformName = "Android", DeviceName = "Galaxy S9", PlatformVersion = "9.0", App = "https://testingbot.com/appium/sample.apk" }; options.AddAdditionalAppiumOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name }); Driver = new AndroidDriver(new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(240)); var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); var inputA = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputA"))); inputA.SendKeys("10"); var inputB = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputB"))); inputB.SendKeys("5"); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.iOS; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; namespace AppiumNunit { [TestFixture] public class iOSSimulatorTest { private IOSDriver? Driver; [Test] public void SampleTest() { var options = new AppiumOptions { PlatformName = "iOS", DeviceName = "iPhone 15", PlatformVersion = "17.4", App = "https://testingbot.com/appium/sample.zip" }; options.AddAdditionalAppiumOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name }); Driver = new IOSDriver(new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(300)); var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); var inputA = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputA"))); inputA.SendKeys("10"); var inputB = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputB"))); inputB.SendKeys("5"); var sum = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("sum"))); Console.WriteLine(sum.Text); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Browsers & Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** Driver = new IOSDriver(new Uri("http://localhost:4444/wd/hub"), options, TimeSpan.FromSeconds(300)); **After:** Driver = new IOSDriver(new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(300)); To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. To see how to do this, please select a combination of device type and device name in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.iOS; using OpenQA.Selenium.Support.UI; using System; using System.Collections.Generic; namespace AppiumNunit { [TestFixture] public class iOSTunnelTest { private IOSDriver? Driver; [Test] public void SampleTest() { var options = new AppiumOptions { PlatformName = "iOS", DeviceName = "iPhone 15", PlatformVersion = "17.4", App = "https://testingbot.com/appium/sample.zip" }; options.AddAdditionalAppiumOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name }); Driver = new IOSDriver(new Uri("http://localhost:4445/wd/hub"), options, TimeSpan.FromSeconds(300)); var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); var inputA = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputA"))); inputA.SendKeys("10"); var inputB = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("inputB"))); inputB.SendKeys("5"); var sum = wait.Until(d => d.FindElement(MobileBy.AccessibilityId("sum"))); Console.WriteLine(sum.Text); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { if (Driver != null) { bool passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; // Logs the result to TestingBot ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); // Terminates the remote webdriver session Driver.Dispose(); } } ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/csharp/specflow # SpecFlow Automated App Testing See our [SpecFlow App example repository](https://github.com/testingbot/specflow-app-example) for a simple example on how to run SpecFlow tests on Mobile Devices with TestingBot. This example project can be used with Visual Studio, or via terminal: `dotnet test`. SpecFlow is an open-source .NET utility which allows you to write tests using Cucumber-compatible Gherkin syntax. ## Installation We'll assume you are using Visual Studio to run your tests. Here are the steps to set up the required environment for your SpecFlow tests: - Add NuGet Packages: `Appium.WebDriver, NUnit, SpecFlow` - For more information, please see the [SpecFlow documentation](https://specflow.org/getting-started/#InstallSetup). In the example below, we'll create a calculator test that enters 2 numbers in 2 input fields and validates the sum. The app used in the example is a demo app we created at TestingBot and runs on both iOS and Android. ## SpecFlow Example First, we'll create the feature file **feature.feature** : Feature: Calculator Scenario Outline: Can do simple math Given I am using the calculator When I add inputA for "5" When I add inputB for "10" Then I should see the sum "15" Now we need to define the logic behind these steps: **SingleStep.cs** using NUnit.Framework; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public class SingleStep { private AppiumDriver _driver; readonly TestingBotDriver _tbDriver; public SingleStep() { _tbDriver = (TestingBotDriver) ScenarioContext.Current["tbDriver"]; } [Given(@"I am using the calculator")] public void GivenIAmOnTheGooglePage() { _driver = _tbDriver.Init(); _driver.LaunchApp(); } [When(@"I add inputA for ""(.*)""")] public void WhenIAddA(string amount) { AndroidElement inputA = _driver.FindElementById("inputA"); inputA.SendKeys(amount); } [When(@"I add inputB for ""(.*)""")] public void WhenIAddB(string amount) { AndroidElement inputB = _driver.FindElementById("inputB"); inputB.SendKeys(amount); } [Then(@"I should see the sum ""(.*)""")] public void ThenIShouldSeeTitle(string sum) { Assert.That(_driver.FindElementByXPath("//android.widget.EditText[@content-desc=\"sum\"]").Text, Is.EqualTo(sum)); } } } Finally, we'll need to create the `TestingBotDriver`: using System; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using OpenQA.Selenium.Appium.Enums; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public sealed class testingbot_specflow { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private AppiumDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public AppiumDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Galaxy S9"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "9.0"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.App, "tb://..."); String key = "TB_KEY"; String secret = "TB_SECRET"; appiumOptions.AddAdditionalCapability("key", key); appiumOptions.AddAdditionalCapability("secret", secret); AppiumDriver driver = new AndroidDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } ## Real Device Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. using System; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using OpenQA.Selenium.Appium.Enums; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public sealed class testingbot_specflow { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private AppiumDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public AppiumDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Galaxy S10"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "10.0"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.App, "tb://..."); appiumOptions.AddAdditionalCapability("realDevice", true); appiumOptions.AddAdditionalCapability("key", Environment.GetEnvironmentVariable("TB_KEY")); appiumOptions.AddAdditionalCapability("secret", Environment.GetEnvironmentVariable("TB_SECRET")); AppiumDriver driver = new AndroidDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. using System; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Enums; using OpenQA.Selenium.Appium.iOS; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public sealed class testingbot_specflow { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private IOSDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public IOSDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "iPhone 15"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "iOS"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "18.0"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.App, "tb://..."); appiumOptions.AddAdditionalCapability("realDevice", true); appiumOptions.AddAdditionalCapability("key", Environment.GetEnvironmentVariable("TB_KEY")); appiumOptions.AddAdditionalCapability("secret", Environment.GetEnvironmentVariable("TB_SECRET")); IOSDriver driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } ## Simulator/Emulator Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. using System; using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using OpenQA.Selenium.Appium.Enums; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public sealed class testingbot_specflow { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private AppiumDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public AppiumDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "Galaxy S9"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "9.0"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.App, "tb://..."); appiumOptions.AddAdditionalCapability("key", Environment.GetEnvironmentVariable("TB_KEY")); appiumOptions.AddAdditionalCapability("secret", Environment.GetEnvironmentVariable("TB_SECRET")); AppiumDriver driver = new AndroidDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. using System; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Enums; using OpenQA.Selenium.Appium.iOS; using TechTalk.SpecFlow; namespace testingbot_specflow { [Binding] public sealed class testingbot_specflow { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private IOSDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public IOSDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.AddAdditionalCapability(MobileCapabilityType.DeviceName, "iPhone 16"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformName, "iOS"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "18.0"); appiumOptions.AddAdditionalCapability(MobileCapabilityType.App, "tb://..."); appiumOptions.AddAdditionalCapability("key", Environment.GetEnvironmentVariable("TB_KEY")); appiumOptions.AddAdditionalCapability("secret", Environment.GetEnvironmentVariable("TB_SECRET")); IOSDriver driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Browsers & Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** IOSDriver driver = new IOSDriver( new Uri("http://localhost:4444/wd/hub"), appiumOptions ); **After:** IOSDriver driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); ### Configuring Capabilities Capabilities are key-value pairs that allows you to customize your tests on TestingBot. Appium provides its [own set of capabilities](https://appium.io/docs/en/2.0/guides/caps/) which you can specify. TestingBot also provide its own [Custom Capabilities](https://testingbot.com/support/app-automate/appium/options), to customize tests ran on the TestingBot platform. You can use the drop-down menus below to see how to configure your tests to run on a specific mobile device: ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace SeleniumTest { class Program { static void Main(string[] args) { IWebDriver driver; DesiredCapabilities capability = DesiredCapabilities.Firefox(); capability.SetCapability("key", "key"); capability.SetCapability("secret", "secret"); capability.SetCapability("version", "latest-1"); driver = new RemoteWebDriver( new Uri("http://localhost:4445/wd/hub/"), capability ); driver.Navigate().GoToUrl("https://www.google.com/ncr"); Console.WriteLine(driver.Title); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); Console.WriteLine(driver.Title); driver.Quit(); } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/csharp/nunit # NUnit Automated App Testing NUnit is a unit-testing framework for all .NET languages. You can use NUnit to run tests on mobile devices, together with Appium. This documentation page will show you how to set up and run Appium tests with NUnit on TestingBot's remote physical device grid. Once you've finished integrating, you will be able to run tests on iOS and Android devices, in parallel, on the remote TestingBot device grid. ## Installation We'll assume you are using Visual Studio to run your tests. Make sure to add these NuGet packages: - `Appium.WebDriver` - `NUnit` ## Initialize remote Appium Webdriver To be able to connect to TestingBot's device grid, we'll need to set up a remote Appium WebDriver. Please see the example file (`TestingBotDriver`) below on how to do this. [Android](https://testingbot.com#)[iOS](https://testingbot.com#) using System; using System.Collections.Generic; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; namespace testingbot { [Binding] public sealed class TestingBot { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private AndroidDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public AndroidDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.PlatformName = "Android"; appiumOptions.AddAdditionalAppiumOption("appium:deviceName", "Galaxy S23"); appiumOptions.AddAdditionalAppiumOption("appium:platformVersion", "13.0"); appiumOptions.AddAdditionalAppiumOption("appium:app", "tb://..."); String key = "TB_KEY"; String secret = "TB_SECRET"; var tbOptions = new Dictionary(); tbOptions.Add("key", key); tbOptions.Add("secret", secret); tbOptions.Add("realDevice", true); appiumOptions.AddAdditionalAppiumOption("tb:options", tbOptions); AndroidDriver driver = new AndroidDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } using System; using System.Collections.Generic; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.iOS; namespace testingbot { [Binding] public sealed class TestingBot { private TestingBotDriver tbDriver; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private IOSDriver driver; private ScenarioContext current; public TestingBotDriver(ScenarioContext current) { this.current = current; } public IOSDriver Init() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.PlatformName = "iOS"; appiumOptions.AddAdditionalAppiumOption("appium:deviceName", "iPhone 15"); appiumOptions.AddAdditionalAppiumOption("appium:platformVersion", "18.0"); appiumOptions.AddAdditionalAppiumOption("appium:app", "tb://..."); String key = "TB_KEY"; String secret = "TB_SECRET"; var tbOptions = new Dictionary(); tbOptions.Add("key", key); tbOptions.Add("secret", secret); tbOptions.Add("realDevice", true); appiumOptions.AddAdditionalAppiumOption("tb:options", tbOptions); IOSDriver driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); return driver; } public void Cleanup() { if (driver != null) { driver.Quit(); } } } } ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** IOSDriver driver = new IOSDriver( new Uri("http://localhost:4444/wd/hub"), appiumOptions ); **After:** IOSDriver driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions ); ### Configuring Capabilities Capabilities are key-value pairs that allows you to customize your tests on TestingBot. Appium provides its [own set of capabilities](https://appium.io/docs/en/2.0/guides/caps/) which you can specify. TestingBot also provide its own [Custom Capabilities](https://testingbot.com/support/app-automate/appium/options), to customize tests ran on the TestingBot platform. You can use the drop-down menus below to see how to configure your tests to run on a specific mobile device: ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a NUnit C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using System; using System.Collections.Generic; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; namespace AppiumTest { class Program { [Test] public void testLocal() { AppiumOptions appiumOptions = new AppiumOptions(); appiumOptions.PlatformName = "Android"; appiumOptions.AddAdditionalAppiumOption("appium:deviceName", "Galaxy S23"); appiumOptions.AddAdditionalAppiumOption("appium:platformVersion", "13.0"); appiumOptions.AddAdditionalAppiumOption("appium:app", "tb://..."); var tbOptions = new Dictionary(); tbOptions.Add("key", "TB_KEY"); tbOptions.Add("secret", "TB_SECRET"); tbOptions.Add("realDevice", true); appiumOptions.AddAdditionalAppiumOption("tb:options", tbOptions); // Point to local tunnel instead of hub.testingbot.com AndroidDriver driver = new AndroidDriver( new Uri("http://localhost:4445/wd/hub"), appiumOptions ); // Perform your app test actions here driver.Quit(); } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different device configurations or run different tests all on the same device configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/flutter # Automated Flutter App Testing TestingBot supports automated testing of Flutter apps via [Appium's Flutter Driver](https://github.com/appium-userland/appium-flutter-driver). To get started, please make sure to follow these steps: 1. Compile your Flutter app in `debug` or `profile` mode. Appium's Flutter driver does not currently support apps built in `release` mode. 2. Make sure your app's `pubspec.yaml` file contains: 3. Import the new `dev_dependencies` that you have added in the previous step: 4. Next, import the `flutter_driver_extension` library in your `main.dart` file: 5. Your `main.dart` file should contain `enableFlutterDriverExtension()` before `runApp`. 6. The `automationName` in your desired capabilities should be set to `Flutter`. ## Preparing your App You can build an `.apk` file for Android, `.ipa` file for iOS physical devices or `.app` bundle for iOS Simulator testing. This file needs to be [uploaded](https://testingbot.com#upload) to TestingBot for automated or manual testing. Please see the table below on how to build your app: OS | Build Mode | Command || Android | debug | flutter build apk --debug | | | profile | flutter build apk --profile | | iOS | debug | flutter build ios --debug | | | simulator | flutter build ios --simulator | | | profile | flutter build ios --profile | - For iOS 14 and higher, please build the app in `profile` mode only. - Release mode is not supported by Appium's Flutter Driver. - For iOS real device testing, please use `flutter build ipa`, then do: mkdir Payload mv Runner.app Payload/ zip --symlinks -qr test-app.ipa Payload ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Example TestingBot has created a [flutter-demo-app](https://github.com/testingbot/flutter-demo-app) which you can use to run your first Flutter Automated test with TestingBot. Please see the example below where we run an automated Flutter test on TestingBot. const { remote } = require('webdriverio'); const assert = require('assert'); const { byValueKey } = require('appium-flutter-finder'); const capabilities = { 'platformName': 'Android', 'appium:deviceName': 'Pixel 8', 'appium:platformVersion': '14.0', 'appium:automationName': 'Flutter', 'appium:app': 'https://github.com/testingbot/flutter-demo-app/releases/download/v1.0.0/demo.apk', 'tb:options': { 'realDevice': true } }; (async () => { const driver = await remote({ hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: 'api_key', key: 'api_secret', capabilities }); const counterTextFinder = byValueKey('counter'); const buttonFinder = byValueKey('incrementButton'); assert.strictEqual(await driver.getElementText(counterTextFinder), '0'); await driver.elementClick(buttonFinder); await driver.elementClick(buttonFinder); assert.strictEqual(await driver.getElementText(counterTextFinder), '2'); await driver.deleteSession(); })(); This example test will open the [flutter-demo-app](https://github.com/testingbot/flutter-demo-app), find both the counter number and increment button by `valueKey`. It will then verify the initial number, click the button twice and verify if the number is correct. You can use the following demo applications to try out automated Flutter testing: - For iOS simulator testing: https://github.com/testingbot/flutter-demo-app/releases/download/v1.0.0/demo-ios-simulator.zip - For iOS physical device testing: https://github.com/testingbot/flutter-demo-app/releases/download/v1.0.0/demo.ipa - For Android testing: https://github.com/testingbot/flutter-demo-app/releases/download/v1.0.0/demo.apk ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote devices. If the test was running on your local machine or network, you can simply change your existing test like this: To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Additional Options Appium provides [multiple Flutter capabilities](https://github.com/appium/appium-flutter-driver#capabilities) to configure your test. Additionally, you can use [Flutter Finders](https://github.com/appium/appium-flutter-driver#Finders) and [Flutter Commands](https://github.com/appium/appium-flutter-driver#commands). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/java ### Java Examples: - [TestNG](https://testingbot.com/support/app-automate/appium/java/testng) # JUnit Automated App Testing See our [JUnit example repository](https://github.com/testingbot/java-junit-app-example) for a simple example on how to run JUnit mobile app tests. ## Installation First, make sure you install the necessary dependencies to run a test. For this example, we'll be using [JUnit 5](https://junit.org/junit5/) and the [Appium Java Client](https://github.com/appium/java-client). Add the following dependencies to your `pom.xml`: org.junit.jupiter junit-jupiter 5.10.2 test io.appium java-client 10.0.0 test **Note:** Appium Java Client 10.x requires Java 11 or higher. ## JUnit Example The example below shows a complete JUnit 5 test that connects to the TestingBot hub and runs a test on a real device. In this test, we'll test a sample calculator app by entering values into two input fields and verifying the sum. [Android](https://testingbot.com#)[iOS](https://testingbot.com#) import io.appium.java_client.AppiumBy; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.options.UiAutomator2Options; import org.junit.jupiter.api.*; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; import static org.junit.jupiter.api.Assertions.assertEquals; public class AndroidAppTest { private AndroidDriver driver; @BeforeEach public void setUp() throws MalformedURLException { // Configure capabilities using UiAutomator2Options UiAutomator2Options options = new UiAutomator2Options() .setPlatformName("Android") .setPlatformVersion("16.0") .setDeviceName("Pixel 9") .setApp("tb://") .setAutomationName("UiAutomator2"); // Add TestingBot-specific options options.setCapability("tb:options", java.util.Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "Android Calculator Test", "build", "JUnit Build 1" )); // Connect to TestingBot hub driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); } @Test public void testCalculatorSum() { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); // Enter first number WebElement inputA = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputA")) ); inputA.sendKeys("10"); // Enter second number WebElement inputB = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputB")) ); inputB.sendKeys("5"); // Verify the sum WebElement sum = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("sum")) ); assertEquals("15", sum.getText()); } @AfterEach public void tearDown() { if (driver != null) { driver.quit(); } } } import io.appium.java_client.AppiumBy; import io.appium.java_client.ios.IOSDriver; import io.appium.java_client.ios.options.XCUITestOptions; import org.junit.jupiter.api.*; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; import static org.junit.jupiter.api.Assertions.assertEquals; public class IOSAppTest { private IOSDriver driver; @BeforeEach public void setUp() throws MalformedURLException { // Configure capabilities using XCUITestOptions XCUITestOptions options = new XCUITestOptions() .setPlatformName("iOS") .setPlatformVersion("26.0") .setDeviceName("iPhone 17") .setApp("tb://") .setAutomationName("XCUITest"); // Add TestingBot-specific options options.setCapability("tb:options", java.util.Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "iOS Calculator Test", "build", "JUnit Build 1" )); // Connect to TestingBot hub driver = new IOSDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); } @Test public void testCalculatorSum() { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); // Enter first number WebElement inputA = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputA")) ); inputA.sendKeys("10"); // Enter second number WebElement inputB = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputB")) ); inputB.sendKeys("5"); // Verify the sum WebElement sum = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("sum")) ); assertEquals("15", sum.getText()); } @AfterEach public void tearDown() { if (driver != null) { driver.quit(); } } } Always call `driver.quit()` in your teardown method to properly end the session. Otherwise, the test will continue running until it times out. ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Browsers & Devices To run your tests on TestingBot, you need to configure the device and platform you want to test on. The Appium Java client provides type-safe Options classes for this purpose. ### Using Options Classes (Recommended) For Android testing, use `UiAutomator2Options`. For iOS testing, use `XCUITestOptions`: [Android](https://testingbot.com#)[iOS](https://testingbot.com#) UiAutomator2Options options = new UiAutomator2Options() .setPlatformName("Android") .setPlatformVersion("16.0") .setDeviceName("Pixel 9") .setApp("tb://") .setAutomationName("UiAutomator2"); // Add TestingBot credentials options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "My Test", "build", "Build 1" )); AndroidDriver driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); XCUITestOptions options = new XCUITestOptions() .setPlatformName("iOS") .setPlatformVersion("26.0") .setDeviceName("iPhone 17") .setApp("tb://") .setAutomationName("XCUITest"); // Add TestingBot credentials options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "My Test", "build", "Build 1" )); IOSDriver driver = new IOSDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); ### Using BaseOptions (Generic) For more flexibility or when working with multiple platforms, you can use `BaseOptions`: import io.appium.java_client.remote.options.BaseOptions; BaseOptions options = new BaseOptions() .setPlatformName("Android") .setAutomationName("UiAutomator2") .amend("appium:deviceName", "Pixel 9") .amend("appium:platformVersion", "16.0") .amend("appium:app", "tb://"); options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET" )); AppiumDriver driver = new AppiumDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); ### Required Capabilities To specify which device you want to test on, you need to provide: - `platformName` - The mobile OS (Android or iOS) - `appium:platformVersion` - The OS version (e.g., "17.0", "26.0") - `appium:deviceName` - The device name (e.g., "Pixel 9", "iPhone 17") - `appium:app` - The app to test (URL or tb:// reference) - `appium:automationName` - The automation driver ("UiAutomator2" for Android, "XCUITest" for iOS) Use the device picker below to generate the configuration for your target device: ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a JUnit test with our Tunnel: **1.** [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret **2.** Update your test to connect through the tunnel instead of directly to the TestingBot hub. Change the URL from `hub.testingbot.com` to `localhost:4445`: // Connect through the tunnel instead of directly to TestingBot AndroidDriver driver = new AndroidDriver( new URL("http://localhost:4445/wd/hub"), options ); Your test traffic will now go securely through the tunnel, allowing you to test apps that access internal resources. ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Please see our [Parallel JUnit documentation](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) for parallel testing. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed TestingBot cannot automatically determine if your test passed or failed - that depends on your test assertions. To report test results to TestingBot, use our [REST API](https://testingbot.com/support/api). First, add the [TestingBot Java client](https://github.com/testingbot/testingbot-java) to your dependencies: com.testingbot testingbotrest 1.0.10 Then use it in your test to report the result: import com.testingbot.comingbotrest.TestingbotREST; import java.util.Map; @AfterEach public void tearDown() { if (driver != null) { // Report test result to TestingBot TestingbotREST api = new TestingbotREST( "YOUR_TB_KEY", "YOUR_TB_SECRET" ); api.updateTest( driver.getSessionId().toString(), Map.of( "success", "1", // "1" for passed, "0" for failed "name", "Calculator Test" ) ); driver.quit(); } } For JUnit 5, you can use a `TestWatcher` extension to automatically report results: import org.junit.jupiter.api.extension.*; public class TestingBotWatcher implements TestWatcher { private final AndroidDriver driver; private final TestingbotREST api; public TestingBotWatcher(AndroidDriver driver, String key, String secret) { this.driver = driver; this.api = new TestingbotREST(key, secret); } @Override public void testSuccessful(ExtensionContext context) { updateTest("1", context.getDisplayName()); } @Override public void testFailed(ExtensionContext context, Throwable cause) { updateTest("0", context.getDisplayName()); } private void updateTest(String success, String name) { api.updateTest(driver.getSessionId().toString(), Map.of( "success", success, "name", name )); } } ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/java/testng # TestNG Automated App Testing See our [TestNG example repository](https://github.com/testingbot/java-testng-app-example) for a simple example on how to run TestNG mobile app tests. ## Installation First, make sure you install the necessary dependencies to run a test. For this example, we'll be using [TestNG](https://testng.org/) and the [Appium Java Client](https://github.com/appium/java-client). Add the following dependencies to your `pom.xml`: org.testng testng 7.11.0 test io.appium java-client 10.0.0 test **Note:** Appium Java Client 10.x requires Java 11 or higher. ## TestNG Example The example below shows a complete TestNG test that connects to the TestingBot hub and runs a test on a real device. In this test, we'll test a sample calculator app by entering values into two input fields and verifying the sum. [Android](https://testingbot.com#)[iOS](https://testingbot.com#) import io.appium.java_client.AppiumBy; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.options.UiAutomator2Options; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.annotations.*; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; import java.util.Map; public class AndroidAppTest { private AndroidDriver driver; @BeforeMethod public void setUp() throws MalformedURLException { // Configure capabilities using UiAutomator2Options UiAutomator2Options options = new UiAutomator2Options() .setPlatformName("Android") .setPlatformVersion("16.0") .setDeviceName("Pixel 9") .setApp("tb://") .setAutomationName("UiAutomator2"); // Add TestingBot-specific options options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "Android Calculator Test", "build", "TestNG Build 1" )); // Connect to TestingBot hub driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); } @Test public void testCalculatorSum() { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); // Enter first number WebElement inputA = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputA")) ); inputA.sendKeys("10"); // Enter second number WebElement inputB = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputB")) ); inputB.sendKeys("5"); // Verify the sum WebElement sum = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("sum")) ); Assert.assertEquals(sum.getText(), "15"); } @AfterMethod public void tearDown() { if (driver != null) { driver.quit(); } } } import io.appium.java_client.AppiumBy; import io.appium.java_client.ios.IOSDriver; import io.appium.java_client.ios.options.XCUITestOptions; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.annotations.*; import java.net.MalformedURLException; import java.net.URL; import java.time.Duration; import java.util.Map; public class IOSAppTest { private IOSDriver driver; @BeforeMethod public void setUp() throws MalformedURLException { // Configure capabilities using XCUITestOptions XCUITestOptions options = new XCUITestOptions() .setPlatformName("iOS") .setPlatformVersion("26.0") .setDeviceName("iPhone 17") .setApp("tb://") .setAutomationName("XCUITest"); // Add TestingBot-specific options options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "iOS Calculator Test", "build", "TestNG Build 1" )); // Connect to TestingBot hub driver = new IOSDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); } @Test public void testCalculatorSum() { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); // Enter first number WebElement inputA = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputA")) ); inputA.sendKeys("10"); // Enter second number WebElement inputB = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputB")) ); inputB.sendKeys("5"); // Verify the sum WebElement sum = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("sum")) ); Assert.assertEquals(sum.getText(), "15"); } @AfterMethod public void tearDown() { if (driver != null) { driver.quit(); } } } Always call `driver.quit()` in your `@AfterMethod` to properly end the session. Otherwise, the test will continue running until it times out. ## Reusable Base Test Class For cleaner test organization, you can create a reusable base class that handles driver setup and teardown. Tests can then extend this base class and focus only on test logic. ### Base Class import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.options.UiAutomator2Options; import org.testng.annotations.*; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; public class TestingBotBaseTest { protected AndroidDriver driver; @BeforeMethod(alwaysRun = true) @Parameters({"platformVersion", "deviceName", "app"}) public void setUp( @Optional("16.0") String platformVersion, @Optional("Pixel 9") String deviceName, @Optional("tb://") String app ) throws MalformedURLException { // Get credentials from environment or use defaults String key = System.getenv("TB_KEY"); String secret = System.getenv("TB_SECRET"); if (key == null || secret == null) { throw new RuntimeException("TB_KEY and TB_SECRET environment variables must be set"); } // Configure capabilities UiAutomator2Options options = new UiAutomator2Options() .setPlatformName("Android") .setPlatformVersion(platformVersion) .setDeviceName(deviceName) .setApp(app) .setAutomationName("UiAutomator2"); options.setCapability("tb:options", Map.of( "key", key, "secret", secret, "name", this.getClass().getSimpleName() )); driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); } @AfterMethod(alwaysRun = true) public void tearDown() { if (driver != null) { driver.quit(); } } } ### Test Class Using the Base import io.appium.java_client.AppiumBy; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.annotations.Test; import java.time.Duration; public class CalculatorTest extends TestingBotBaseTest { @Test public void testAddition() { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); WebElement inputA = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputA")) ); inputA.sendKeys("10"); WebElement inputB = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("inputB")) ); inputB.sendKeys("5"); WebElement sum = wait.until( ExpectedConditions.elementToBeClickable(AppiumBy.accessibilityId("sum")) ); Assert.assertEquals(sum.getText(), "15"); } } ### TestNG XML Configuration Use a `testng.xml` file to pass parameters and run tests on multiple devices: ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Browsers & Devices To run your tests on TestingBot, you need to configure the device and platform you want to test on. The Appium Java client provides type-safe Options classes for this purpose. ### Using Options Classes (Recommended) For Android testing, use `UiAutomator2Options`. For iOS testing, use `XCUITestOptions`: [Android](https://testingbot.com#)[iOS](https://testingbot.com#) UiAutomator2Options options = new UiAutomator2Options() .setPlatformName("Android") .setPlatformVersion("16.0") .setDeviceName("Pixel 9") .setApp("tb://") .setAutomationName("UiAutomator2"); // Add TestingBot credentials options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "My Test", "build", "Build 1" )); AndroidDriver driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); XCUITestOptions options = new XCUITestOptions() .setPlatformName("iOS") .setPlatformVersion("26.0") .setDeviceName("iPhone 17") .setApp("tb://") .setAutomationName("XCUITest"); // Add TestingBot credentials options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET", "name", "My Test", "build", "Build 1" )); IOSDriver driver = new IOSDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); ### Using BaseOptions (Generic) For more flexibility or when working with multiple platforms, you can use `BaseOptions`: import io.appium.java_client.remote.options.BaseOptions; BaseOptions options = new BaseOptions() .setPlatformName("Android") .setAutomationName("UiAutomator2") .amend("appium:deviceName", "Pixel 9") .amend("appium:platformVersion", "16.0") .amend("appium:app", "tb://"); options.setCapability("tb:options", Map.of( "key", "YOUR_TB_KEY", "secret", "YOUR_TB_SECRET" )); AppiumDriver driver = new AppiumDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); ### Required Capabilities To specify which device you want to test on, you need to provide: - `platformName` - The mobile OS (Android or iOS) - `appium:platformVersion` - The OS version (e.g., "16.0", "26.0") - `appium:deviceName` - The device name (e.g., "Pixel 9", "iPhone 17") - `appium:app` - The app to test (URL or tb:// reference) - `appium:automationName` - The automation driver ("UiAutomator2" for Android, "XCUITest" for iOS) Use the device picker below to generate the configuration for your target device: ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a TestNG test with our Tunnel: **1.** [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret **2.** Update your test to connect through the tunnel instead of directly to the TestingBot hub. Change the URL from `hub.testingbot.com` to `localhost:4445`: // Connect through the tunnel instead of directly to TestingBot AndroidDriver driver = new AndroidDriver( new URL("http://localhost:4445/wd/hub"), options ); Your test traffic will now go securely through the tunnel, allowing you to test apps that access internal resources. ## Mark tests as passed/failed TestingBot cannot automatically determine if your test passed or failed - that depends on your test assertions. To report test results to TestingBot, use our [REST API](https://testingbot.com/support/api). First, add the [TestingBot Java client](https://github.com/testingbot/testingbot-java) to your dependencies: com.testingbot testingbotrest 1.0.10 Then use it in your test to report the result: import com.testingbot.comingbotrest.TestingbotREST; import java.util.Map; @AfterMethod public void tearDown() { if (driver != null) { // Report test result to TestingBot TestingbotREST api = new TestingbotREST( "YOUR_TB_KEY", "YOUR_TB_SECRET" ); api.updateTest( driver.getSessionId().toString(), Map.of( "success", "1", // "1" for passed, "0" for failed "name", "Calculator Test" ) ); driver.quit(); } } For automatic result reporting, you can use a TestNG listener: import org.testng.ITestListener; import org.testng.ITestResult; import com.testingbot.comingbotrest.TestingbotREST; import java.util.Map; public class TestingBotListener implements ITestListener { private TestingbotREST api; public TestingBotListener() { this.api = new TestingbotREST( System.getenv("TB_KEY"), System.getenv("TB_SECRET") ); } @Override public void onTestSuccess(ITestResult result) { updateTestStatus(result, "1"); } @Override public void onTestFailure(ITestResult result) { updateTestStatus(result, "0"); } private void updateTestStatus(ITestResult result, String success) { Object testInstance = result.getInstance(); if (testInstance instanceof TestingBotBaseTest) { AndroidDriver driver = ((TestingBotBaseTest) testInstance).driver; if (driver != null) { api.updateTest( driver.getSessionId().toString(), Map.of( "success", success, "name", result.getMethod().getMethodName() ) ); } } } } Register the listener in your `testng.xml`: ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/nodejs ### NodeJS Examples: - [WebDriverIO](https://testingbot.com/support/app-automate/appium/nodejs/webdriverio) - [CodeceptJS](https://testingbot.com/support/app-automate/appium/nodejs/codeceptjs) # NodeJS Automated App Testing First, make sure you have installed NodeJS. If you haven't, you can easily install it by downloading NodeJS from the [NodeJS website](https://nodejs.org/en/download/) ## Installation With TestingBot you can easily run your automated tests with any NodeJS test framework, here's a simple example with **WebdriverIO** : npm install webdriverio ## Real Device Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. const { remote } = require('webdriverio'); const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: "api_key", key: "api_secret", capabilities: { 'appium:name': 'My First App Test', 'appium:deviceName': 'Pixel 9', 'platformName': 'Android', 'appium:platformVersion': '16.0', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'tb:options': { 'realDevice': true } } }; (async () => { const driver = await remote(capabilities); const inputA = await driver.$('~inputA'); await inputA.waitForDisplayed({ timeout: 30000 }); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.waitForDisplayed({ timeout: 30000 }); await inputB.setValue('5'); const sum = await driver.$('~sum'); await sum.waitForDisplayed({ timeout: 30000 }); const value = await sum.getText(); console.log(value === '15' ? 'Test passed!' : 'Test failed!'); await driver.deleteSession(); })(); Make sure to always end your session (`await driver.deleteSession()`), otherwise it will continue running, leading to a timeout. This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. const { remote } = require('webdriverio'); const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: "api_key", key: "api_secret", capabilities: { 'appium:name': 'My First App Test', 'appium:deviceName': 'iPhone 17', 'platformName': 'iOS', 'appium:platformVersion': '26.0', 'appium:app': 'https://testingbot.com/appium/sample.ipa', 'tb:options': { 'realDevice': true } } }; (async () => { const driver = await remote(capabilities); const inputA = await driver.$('~inputA'); await inputA.waitForDisplayed({ timeout: 30000 }); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.waitForDisplayed({ timeout: 30000 }); await inputB.setValue('5'); await driver.deleteSession(); })(); Make sure to always end your session (`await driver.deleteSession()`), otherwise it will continue running, leading to a timeout. ## Simulator/Emulator Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) This will download and install a sample Android app we built. It will add two numbers to a textinput and display the sum of the two numbers. const { remote } = require('webdriverio'); const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: "api_key", key: "api_secret", capabilities: { 'appium:name': 'My First App Test', 'appium:deviceName': 'Pixel 9', 'platformName': 'Android', 'appium:platformVersion': '16.0', 'appium:app': 'https://testingbot.com/appium/sample.apk' } }; (async () => { const driver = await remote(capabilities); const inputA = await driver.$('~inputA'); await inputA.waitForDisplayed({ timeout: 30000 }); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.waitForDisplayed({ timeout: 30000 }); await inputB.setValue('5'); const sum = await driver.$('~sum'); await sum.waitForDisplayed({ timeout: 30000 }); const value = await sum.getText(); console.log(value === '15' ? 'Test passed!' : 'Test failed!'); await driver.deleteSession(); })(); Make sure to always end your session (`await driver.deleteSession()`), otherwise it will continue running, leading to a timeout. This will download and install a sample iOS app we built. It will add two numbers to a textinput and display the sum of the two numbers. const { remote } = require('webdriverio'); const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: "api_key", key: "api_secret", capabilities: { 'appium:name': 'My First App Test', 'appium:deviceName': 'iPhone 17', 'platformName': 'iOS', 'appium:platformVersion': '26.0', 'appium:app': 'https://testingbot.com/appium/sample.zip' } }; (async () => { const driver = await remote(capabilities); const inputA = await driver.$('~inputA'); await inputA.waitForDisplayed({ timeout: 30000 }); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.waitForDisplayed({ timeout: 30000 }); await inputB.setValue('5'); await driver.deleteSession(); })(); Make sure to always end your session (`await driver.deleteSession()`), otherwise it will continue running, leading to a timeout. ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** const capabilities = { hostname: 'localhost', port: 4444, ... }; **After:** const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: 'api_key', key: 'api_secret', capabilities: { 'appium:app': 'tb://...' } }; To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. To see how to do this, please select a combination of device type and device name in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a NodeJS test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: const { remote } = require('webdriverio'); const capabilities = { hostname: 'localhost', port: 4445, protocol: 'http', path: '/wd/hub', user: "api_key", key: "api_secret", capabilities: { 'appium:name': 'My First App Test', 'appium:deviceName': 'iPhone 17', 'platformName': 'iOS', 'appium:platformVersion': '26.0', 'appium:app': 'https://testingbot.com/appium/sample.zip' } }; (async () => { const driver = await remote(capabilities); const inputA = await driver.$('~inputA'); await inputA.waitForDisplayed({ timeout: 30000 }); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.waitForDisplayed({ timeout: 30000 }); await inputB.setValue('5'); await driver.deleteSession(); })(); ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using a test runner like [WebDriverIO](https://testingbot.com/support/app-automate/appium/nodejs/webdriverio) to run your tests simultaneously. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. Install our NPM package to interact with the TestingBot API: npm install testingbot-api After your test completed, you can send back the test success state and other meta-data: const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: "api_key", api_secret: "api_secret" }); tb.updateTest({ 'test[name]' : 'Example Test', 'test[success]' : true }, browser.sessionId, done); ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/nodejs/codeceptjs # Getting started with CodeceptJS [CodeceptJS](https://codecept.io/) is an end-to-end testing framework which supports Appium for automated mobile testing. It offers scenario driven testing, PageObjects support, beautiful reports and much more. Let's start with installing everything we need: npm i --save-dev codeceptjs Now we need to set up CodeceptJS. Please use the command below to initialize a new project: npx codeceptjs init This will ask a bunch of questions, and will create a sample test at the end of the process. ## Example test Now that you have everything set up, you can create a very simple test: Feature('My First Mobile App Test'); Scenario('test sample calculator', (I) => { I.seeAppIsInstalled("com.testingbot.sample"); I.click('~inputA'); I.fillField('~inputA', '10'); I.click('~inputB'); I.fillField('~inputB', '5'); I.see('15', '~sum'); }); This simple test will test a calculator mobile app, it will fill in two numbers in two input fields and check the sum. Before we can run this test, we need to configure CodeceptJS to connect to TestingBot. ## Configuration You can configure CodeceptJS with a `codecept.conf.js` file: exports.config = { tests: './*_test.js', output: './output', helpers: { Appium: { host: "hub.testingbot.com", port: 443, user: "api_key", key: "api_secret", capabilities: { platformName: "Android", "appium:app": "tb://...", "appium:deviceName": "Pixel 8", "appium:platformVersion": "14.0", "appium:automationName": "UiAutomator2" }, }, }, include: { I: './steps_file.js' }, bootstrap: null, mocha: {}, name: 'codeceptjs-example', plugins: { retryFailedStep: { enabled: true }, screenshotOnFail: { enabled: true }, } } To run the test, you can do: npx codeceptjs run --steps This will start a Pixel 8 Emulator and run the test on our grid. You will see a test appear in your member dashboard on TestingBot, together with a video, log files and other assets generated by the test. ## Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before** // codecept.conf.js exports.config = { tests: './*_test.js', output: './output', helpers: { Appium : {} } }; **After** // codecept.conf.js helpers: { Appium: { host: "hub.testingbot.com", port: 443, user: "api_key", key: "api_secret", capabilities: { platformName: "Android", "appium:app": "tb://...", "appium:deviceName": "Pixel 8", "appium:platformVersion": "14.0", "appium:automationName": "UiAutomator2" }, }, }, ### Specifying the device To let TestingBot know on which device you want to run your test on, you need to specify the deviceName and platformName. To see how to do this, please select a combination of deviceName and platformName in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Mark tests as passed/failed CodeceptJS allows you to mark tests as passed or failed, which is useful for debugging and reporting purposes. You can use the `I.see()` and `I.dontSee()` methods to check for specific elements or text on the page. If the element is not found, the test will fail. This is useful for checking if a specific element is present on the page, or if a specific text is visible. If the element or text is not found, the test will fail and you will see an error message in the report. ## Parallel Testing Please see [CodeceptJS parallel testing](https://codecept.io/parallel/#parallel-execution-by-workers) on how to run your tests in parallel. You can specify the concurrency by specifying a number of workers: npx codeceptjs run-workers 2 or run multiple different devices with: npx codeceptjs run-multiple --all ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/nodejs/webdriverio # WebDriverIO Automated App Testing First, make sure you have installed NodeJS. If you haven't, you can easily install it by [downloading NodeJS](https://nodejs.org/en/download/). See our [WebdriverIO examples repository](https://github.com/testingbot/webdriverio-examples) for some examples on how to use WebdriverIO with TestingBot. ## Installation TestingBot has its own [WebDriverIO service](https://webdriver.io/docs/testingbot-service.html) plugin which makes configuring your tests easier and which sends test meta-data back to TestingBot. Let's start with making sure `webdriverio` is installed: npm i --save-dev @wdio/cli @wdio/local-runner You are now ready to run a WebDriver test with NodeJS on our grid. ## WebDriverIO TestingBot Service WebDriverIO contains a [TestingBot service](https://webdriver.io/docs/testingbot-service.html) which makes it easy to run tests with WebDriverIO on TestingBot. With this service, WebDriverIO will start a [TestingBot Tunnel](https://testingbot.com/support/tunnel) if required, and send back test meta-data (passed state, name, build-id, ...) In order to use the service you need to download it from NPM: npm install @wdio/testingbot-service --save-dev ## Mocha Example To run Mocha tests on TestingBot, please follow these steps: npm install @wdio/testingbot-service --save-dev npm install @wdio/dot-reporter --save-dev npm install @wdio/mocha-framework --save-dev Now we'll make a simple Mocha test which uses Firefox on TestingBot to go to Google.com and verify the page's title. Please create the following files: **wdio.conf.js** exports.config = { /** * specify test files */ specs: [ './runner-specs/mocha.test.js' ], /** * capabilities */ capabilities: [{ platformName: 'Android', 'appium:deviceName': 'Pixel 8', 'appium:platformVersion': '14.0', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'tb:options': { name: 'My First App Test' } }], /** * test configurations */ logLevel: 'silent', coloredLogs: true, screenshotPath: 'screenshots', waitforTimeout: 10000, connectionRetryTimeout: 480000, framework: 'mocha', services: [ ['testingbot'] ], user: 'api_key', key: 'api_secret', reporters: ['dot'], reporterOptions: { outputDir: './' }, mochaOpts: { ui: 'bdd' } }; **runner-specs/mocha.test.js** const assert = require('assert') describe('calculator', function() { it('should calculate a sum', async () => { const inputA = await $('~inputA') await inputA.waitForDisplayed(5000) await inputA.click() try { await inputA.addValue('10') } catch (e) {} const inputB = await $('~inputB') await inputB.waitForDisplayed(5000) await inputB.click() try { await inputB.addValue('5') } catch (e) {} const sumElement = await $('~sum') const sum = await sumElement.getText() assert.equal(sum, '15') // 10 + 5 }) }) Now we can run this mobile app test on TestingBot. The test will do a simple sum calculation and verify if the calculation was correct. To start the test, please run this command: ~/node_modules/.bin/wdio run wdio.conf.js The test will now run on TestingBot. At the end of the test, the testname and success state will be available on TestingBot, together with a video and other meta-data. ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** exports.config = { // ... services: ['selenium-standalone'], // ... }; **After:** exports.config = { // ... services: [ ['testingbot'] ], user: process.env.TB_KEY, key: process.env.TB_SECRET, // ... }; To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. To see how to do this, please select a combination of device type and device name in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a WebdriverIO test with our Tunnel: 1. Adjust your `wdio.conf.js` configuration to use `tbTunnel: true`. The [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) will automatically download and use the tunnel for your tests. **wdio.conf.js** exports.config = { services: [ ['testingbot', { tbTunnel: true }] ], user: 'api_key', key: 'api_secret' }; ## Run Tests in Parallel Parallel testing allows you to run multiple tests at the same time, significantly reducing your total test execution time. You can run the same test across different device configurations, or run different tests on the same configuration — all simultaneously. TestingBot provides a large grid of browsers and devices, enabling you to run tests in parallel efficiently. This is one of our core features designed to help you test faster and ship more reliably. With WebDriverIO, you can enable parallel test execution by setting the `maxInstances` property in your `wdio.conf.js` file and specifying multiple `capabilities`. This defines how many instances of the same browser can run in parallel. We recommend setting this value to match the number of parallel sessions allowed by your TestingBot plan. exports.config = { maxInstances: 5, // Adjust this based on your TestingBot plan capabilities: [{ platformName: 'Android', 'appium:deviceName': 'Pixel 8', 'appium:platformVersion': '14.0', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'tb:options': { name: 'My First App Test' } }, { platformName: 'Android', 'appium:deviceName': 'Pixel 9', 'appium:platformVersion': '15.0', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'tb:options': { name: 'My Second App Test' } }] }; ### Queuing Every TestingBot plan includes a fixed number of parallel test slots. If you exceed this limit, additional tests will be automatically queued and executed as soon as slots become available, no tests will be dropped or skipped. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. If you are using the [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) then your tests will automatically report back meta-data to TestingBot (like test success, name, stacktrace, ...) ## Common errors Below are some common errors you might encounter when running WebDriverIO tests on TestingBot: - `UND_ERR_HEADERS_TIMEOUT` **Problem:** This error indicates that WebdriverIO did not receive a response in time. This might happen when requesting a device that is currently in use, or in case you are trying to run more tests in parallel than your plan allows and the tests have been [queued](https://testingbot.com#queuing) for a long time. **Solution:** You can try adding the `connectionRetryTimeout` in your WebDriverIO configuration with a high enough value: connectionRetryTimeout: 480000 ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/php # PHPUnit Automated App Testing See our [PHPUnit Mobile example repository](https://github.com/testingbot/php-phpunit-mobile-example) for a simple example on how to run PHPUnit tests for Mobile Apps on TestingBot. Let's start with making sure PHP is available on your system. **For Windows:** - You can download PHP for Windows from [PHP For Windows](https://windows.php.net/download/). - Run the installer and follow the setup wizard to install PHP. **For Linux:** sudo apt-get install curl libcurl3 libcurl3-dev php **For macOS:** PHP should already be present on macOS by default. ## Install PHPUnit - Make sure you have [Composer installed](https://getcomposer.org/). - Install PHPUnit by running this command in your terminal: - Install Appium PHP Client by running this command in your terminal: ## PHPUnit Example Real Devices Please see the example below. We're going to test our sample app on a Real Device. In this test we'll add values to two input fields and see if the calculator works. [Android](https://testingbot.com#)[iOS](https://testingbot.com#) '', 'desiredCapabilities' => array( 'app' => 'https://testingbot.com/appium/sample.apk', 'deviceName' => 'Galaxy S8', 'version' => '9.0', 'platformName' => 'Android', 'realDevice': true ))); public function setupSpecificBrowser($params) { $caps = $this->getDesiredCapabilities(); $this->setHost('api_key:api_secret@hub.testingbot.com'); $caps = isset($params['desiredCapabilities']) ? $params['desiredCapabilities'] : array(); $this->setDesiredCapabilities($caps); $this->setUpSessionStrategy($params); $this->setSeleniumServerRequestsTimeout(180); } public function testNativeApplication() { $el = $this->byAccessibilityId('inputA'); $el->click(); $this->keys("10"); $el = $this->byAccessibilityId('inputB'); $el->click(); $this->keys("5"); } } '', 'desiredCapabilities' => array( 'app' => 'https://testingbot.com/appium/sample.ipa', 'deviceName' => 'iPhone XR', 'version' => '16.3', 'platformName' => 'iOS', 'realDevice': true ))); public function setupSpecificBrowser($params) { $caps = $this->getDesiredCapabilities(); $this->setHost('api_key:api_secret@hub.testingbot.com'); $caps = isset($params['desiredCapabilities']) ? $params['desiredCapabilities'] : array(); $this->setDesiredCapabilities($caps); $this->setUpSessionStrategy($params); $this->setSeleniumServerRequestsTimeout(180); } public function testNativeApplication() { $el = $this->byAccessibilityId('inputA'); $el->click(); $this->keys("10"); $el = $this->byAccessibilityId('inputB'); $el->click(); $this->keys("5"); } } ## PHPUnit Example Simulator/Emulator Please see the example below. We're going to test our sample app on an iOS Simulator or Android Emulator. In this test we'll add values to two input fields and see if the calculator works. [Android](https://testingbot.com#)[iOS](https://testingbot.com#) '', 'desiredCapabilities' => array( 'app' => 'https://testingbot.com/appium/sample.apk', 'deviceName' => 'Pixel 8', 'version' => '14.0', 'platformName' => 'Android' ))); public function setupSpecificBrowser($params) { $caps = $this->getDesiredCapabilities(); $this->setHost('api_key:api_secret@hub.testingbot.com'); $caps = isset($params['desiredCapabilities']) ? $params['desiredCapabilities'] : array(); $this->setDesiredCapabilities($caps); $this->setUpSessionStrategy($params); $this->setSeleniumServerRequestsTimeout(180); } public function testNativeApplication() { $el = $this->byAccessibilityId('inputA'); $el->click(); $this->keys("10"); $el = $this->byAccessibilityId('inputB'); $el->click(); $this->keys("5"); } } '', 'desiredCapabilities' => array( 'app' => 'https://testingbot.com/appium/sample.zip', 'deviceName' => 'iPhone 15', 'version' => '17.4', 'platformName' => 'iOS' ))); public function setupSpecificBrowser($params) { $caps = $this->getDesiredCapabilities(); $this->setHost('api_key:api_secret@hub.testingbot.com'); $caps = isset($params['desiredCapabilities']) ? $params['desiredCapabilities'] : array(); $this->setDesiredCapabilities($caps); $this->setUpSessionStrategy($params); $this->setSeleniumServerRequestsTimeout(180); } public function testNativeApplication() { $el = $this->byAccessibilityId('inputA'); $el->click(); $this->keys("10"); $el = $this->byAccessibilityId('inputB'); $el->click(); $this->keys("5"); } } ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Browsers & Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: $this->setHost('api_key:api_secret@hub.testingbot.com'); To let TestingBot know on which device you want to run your test on, you need to specify the `deviceName`, `version`, `platformName` and other optional options in the capabilities field. public static $browsers = array(array( 'browserName' => '', 'desiredCapabilities' => array( 'app' => 'tb://...', 'deviceName' => 'iPhone 15', 'version' => '17.4', 'platformName' => 'iOS' ))); To see how to do this, please select a combination of device type and device name in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PHP WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: '', 'desiredCapabilities' => array( 'app' => 'https://testingbot.com/appium/sample.zip', 'deviceName' => 'iPhone 15', 'version' => '17.4', 'platformName' => 'iOS' ))); public function setupSpecificBrowser($params) { $caps = $this->getDesiredCapabilities(); $this->setHost('api_key:api_secret@localhost'); $this->setPort(4445); $caps = isset($params['desiredCapabilities']) ? $params['desiredCapabilities'] : array(); $this->setDesiredCapabilities($caps); $this->setUpSessionStrategy($params); $this->setSeleniumServerRequestsTimeout(180); } public function testNativeApplication() { $el = $this->byAccessibilityId('inputA'); $el->click(); $this->keys("10"); $el = $this->byAccessibilityId('inputB'); $el->click(); $this->keys("5"); } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using [Paratest](https://github.com/brianium/paratest), which makes it very easy to run multiple PHPUnit tests simultaneously. vendor/bin/paratest -p 8 -f --phpunit=vendor/bin/phpunit WebdriverTest.php The command above will run your tests in 8 separate processes (8 tests at once). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [PHP API client](https://github.com/testingbot/testingbot-php) to report back test results. $api = new TestingBot\TestingBotAPI($apiKey, $apiSecret); $api->updateJob($web_driver->getSessionID(), array('name' => 'mytest', 'success' => true)); ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/proxy # Configure a device with a proxy You can use Appium or Selenium WebDriver to configure a proxy on the remote Android or iOS device, at the start of your test. This makes sure that all traffic on the device will go through the external proxy, which can be useful to do [geolocation testing](https://testingbot.com/support/app-automate/appium/options#geo) or latency testing. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) desired_caps = { 'platformName' => 'Android', 'appium:deviceName' => 'Pixel 9', 'appium:platformVersion' => '16.0', 'appium:app' => 'https://testingbot.com/appium/sample.apk', 'tb:options' => { 'realDevice' => true } } # Set up the proxy settings proxy = { 'proxyType' => 'manual', # Proxy type (manual or system) 'httpProxy' => 'http://your-proxy-server:8080', # Replace with your HTTP proxy URL 'sslProxy' => 'http://your-proxy-server:8080', # Replace with your SSL proxy URL 'noProxy' => 'localhost,127.0.0.1' # Optional: bypass proxy for specific hosts } # Add proxy to desired capabilities desired_caps['proxy'] = proxy # Initialize the Appium driver driver = Appium::Driver.new({caps: desired_caps}, true) UiAutomator2Options options = new UiAutomator2Options(); // Set basic capabilities options.setPlatformName("Android"); options.setCapability("appium:deviceName", "Pixel 9"); options.setCapability("appium:platformVersion", "16.0"); options.setCapability("appium:app", "https://testingbot.com/appium/sample.apk"); // Set TestingBot-specific options Map tbOptions = new HashMap<>(); tbOptions.put("realDevice", true); options.setCapability("tb:options", tbOptions); // Set up proxy settings Proxy proxy = new Proxy(); proxy.setHttpProxy("http://your-proxy-server:8080"); // Replace with your HTTP proxy URL proxy.setSslProxy("http://your-proxy-server:8080"); // Replace with your SSL proxy URL // Apply the proxy settings to the capabilities options.setProxy(proxy); // Initialize the driver with TestingBot Appium server URL URL appiumServerUrl = new URL("https://hub.testingbot.com/wd/hub"); AndroidDriver driver = new AndroidDriver(appiumServerUrl, options); $capabilities = array( 'platformName' => 'Android', 'appium:app' => 'https://testingbot.com/appium/sample.apk', 'appium:deviceName' => 'Pixel 9', 'appium:platformVersion' => '16.0', 'tb:options' => array( 'realDevice' => true ), 'proxy' => array( 'proxyType' => 'manual', // Proxy type, "manual" for custom proxy settings 'httpProxy' => 'http://your-proxy-server:8080', // Replace with your HTTP proxy 'sslProxy' => 'http://your-proxy-server:8080', // Replace with your SSL proxy (HTTPS traffic) 'noProxy' => 'localhost,127.0.0.1' // Optional: addresses that should bypass the proxy ) ); $web_driver = RemoteWebDriver::create('https://hub.testingbot.com/wd/hub', $capabilities, null, null, PROXY_URL, PROXY_PORT); capabilities = { "platformName": "Android", "appium:deviceName": "Pixel 9", "appium:platformVersion": "16.0", "appium:app": "https://testingbot.com/appium/sample.apk", "tb:options": { "realDevice": True }, "proxy": { "proxyType": "manual", # Or "system" if you want to use system proxy "httpProxy": "http://your-proxy-server:8080", # Replace with your proxy server "sslProxy": "http://your-proxy-server:8080", # Replace with your proxy server for SSL "noProxy": "localhost,127.0.0.1" # Optional: specify addresses to bypass the proxy } } driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=capabilities ) const { remote } = require('webdriverio'); const capabilities = { hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: 'api_key', key: 'api_secret', capabilities: { 'platformName': 'Android', 'appium:deviceName': 'Pixel 9', 'appium:platformVersion': '16.0', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'tb:options': { 'name': 'My First App Test', 'realDevice': true }, 'proxy': { proxyType: 'manual', httpProxy: 'http://proxy-server:8080', // Replace with your proxy server URL sslProxy: 'http://proxy-server:8080', // If needed for SSL connections noProxy: '' // You can define URLs to bypass the proxy } } }; const driver = await remote(capabilities); AppiumOptions options = new AppiumOptions(); options.PlatformName = "Android"; options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9"); options.AddAdditionalAppiumOption("appium:platformVersion", "16.0"); options.AddAdditionalAppiumOption("appium:app", "https://testingbot.com/appium/sample.apk"); // Set TestingBot-specific options var tbOptions = new Dictionary { ["realDevice"] = true }; options.AddAdditionalAppiumOption("tb:options", tbOptions); // Set up proxy using the Proxy class Proxy proxy = new Proxy(); proxy.HttpProxy = "http://your-proxy-server:8080"; // Replace with your proxy URL proxy.SslProxy = "http://your-proxy-server:8080"; // Replace with your proxy URL proxy.NoProxy = "localhost,127.0.0.1"; // Optional: bypass proxy for specific addresses // Apply the proxy to the Appium options options.Proxy = proxy; // Initialize the driver AndroidDriver driver = new AndroidDriver(new Uri("https://hub.testingbot.com/wd/hub"), options); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/python # Python Automated App Testing Before you can start testing apps with Python, let's start with making sure Python is available on your system. **For Windows:** - Download the latest python installer for Windows: [Python Releases for Windows](https://www.python.org/downloads/windows/) - Run the installer and follow the setup wizard to install Python. **For Linux/macOS:** - macOS, Ubuntu and most other Linux distros come with Python pre-installed. ## Installation With TestingBot you can easily run automated tests with Python against your mobile app. To get started, please install the following libraries: easy_install pip pip install Appium-Python-Client pip install selenium ### Real Device Example [Android](https://testingbot.com#)[iOS](https://testingbot.com#) Below is a Python Example, this will download and install our sample app (a calculator), add numbers to two input fields and show the sum of the two numbers: from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC capabilities = { "platformName": "Android", "appium:deviceName": "Galaxy S24", "appium:platformVersion": "14.0", "appium:app": "https://testingbot.com/appium/sample.apk", "tb:options": { "key": "api_key", "secret": "api_secret", "realDevice": True } } driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", capabilities) inputA = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputA")) ) inputA.send_keys("10") inputB = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputB")) ) inputB.send_keys("5") sum_element = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "sum")) ) assert sum_element.text == "15", "Sum should be 15" driver.quit() from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC capabilities = { "platformName": "iOS", "appium:deviceName": "iPhone 15", "appium:platformVersion": "18.0", "appium:app": "https://testingbot.com/appium/sample.ipa", "tb:options": { "key": "api_key", "secret": "api_secret", "realDevice": True } } driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", capabilities) inputA = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputA")) ) inputA.send_keys("10") inputB = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputB")) ) inputB.send_keys("5") driver.quit() ### Simulator/Emulator Example [Android](https://testingbot.com#)[iOS](https://testingbot.com#) Below is a Python Example, this will download and install our sample app (a calculator), add numbers to two input fields and show the sum of the two numbers: from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC capabilities = { "platformName": "Android", "appium:deviceName": "Pixel 8", "appium:platformVersion": "14.0", "appium:app": "https://testingbot.com/appium/sample.apk", "tb:options": { "key": "api_key", "secret": "api_secret" } } driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", capabilities) inputA = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputA")) ) inputA.send_keys("10") inputB = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputB")) ) inputB.send_keys("5") sum_element = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "sum")) ) assert sum_element.text == "15", "Sum should be 15" driver.quit() from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC capabilities = { "platformName": "iOS", "appium:deviceName": "iPhone 15", "appium:platformVersion": "17.4", "appium:app": "https://testingbot.com/appium/sample.zip", "tb:options": { "key": "api_key", "secret": "api_secret" } } driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", capabilities) inputA = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputA")) ) inputA.send_keys("10") inputB = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputB")) ) inputB.send_keys("5") driver.quit() Make sure to always stop your test (`driver.quit()`), otherwise it will continue running, leading to a timeout. ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = webdriver.Remote("http://localhost:4723/wd/hub", capabilities) **After:** driver = webdriver.Remote("https://hub.testingbot.com/wd/hub", capabilities) To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Python test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC capabilities = { "platformName": "iOS", "appium:deviceName": "iPhone 15", "appium:platformVersion": "17.4", "appium:app": "https://testingbot.com/appium/sample.zip", "tb:options": { "key": "api_key", "secret": "api_secret" } } # Point to local tunnel instead of hub.testingbot.com driver = webdriver.Remote("http://localhost:4445/wd/hub", capabilities) inputA = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputA")) ) inputA.send_keys("10") inputB = WebDriverWait(driver, 30).until( EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "inputB")) ) inputB.send_keys("5") driver.quit() ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different device configurations or run different tests all on the same device configuration. TestingBot has a large grid of devices, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using pytest with pytest-xdist, which makes it very easy to run multiple Python tests simultaneously: pip install pytest pytest-xdist pytest -n ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/ruby # Ruby Automated App Testing Let's start with making sure Ruby is available on your system. **For Windows:** - You can download Ruby for Windows from [RubyInstaller](https://rubyinstaller.org/) - Run the installer and follow the setup wizard to install Ruby. **For Linux/macOS:** Download [RVM](https://rvm.io/) and install Ruby: curl -L https://get.rvm.io | bash -s stable --ruby ## Installation With TestingBot you can easily run your automated app tests with Ruby. Please install the following gems: gem install appium_lib gem install selenium-webdriver Please see the example below. We're going to run a test on our sample app (calculator) where we'll add values to two input fields. ### Real Device Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) require 'appium_lib' caps = { "platformName" => "Android", "appium:deviceName" => "Galaxy S24", "appium:platformVersion" => "14.0", "appium:app" => "https://testingbot.com/appium/sample.apk", "tb:options" => { "name" => "Ruby Appium Example", "realDevice" => true } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) wait.until { driver.find_element(:accessibility_id, "inputA").displayed? } driver.find_element(:accessibility_id, "inputA").send_keys 5 driver.find_element(:accessibility_id, "inputB").send_keys 10 result = driver.find_element(:accessibility_id, "sum") if (!result.nil?) && (result.text.eql? "15") puts "Test Passed" else puts "Test Failed" end driver.quit require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "18.0", "appium:app" => "https://testingbot.com/appium/sample.ipa", "tb:options" => { "name" => "Ruby Appium Example", "realDevice" => true } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) driver.find_element(:accessibility_id, "inputA").send_keys 5 driver.find_element(:accessibility_id, "inputB").send_keys 10 driver.quit ### Simulator/Emulator Testing [Android](https://testingbot.com#)[iOS](https://testingbot.com#) require 'appium_lib' caps = { "platformName" => "Android", "appium:deviceName" => "Pixel 8", "appium:platformVersion" => "14.0", "appium:app" => "https://testingbot.com/appium/sample.apk", "tb:options" => { "name" => "Ruby Appium Example" } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) wait.until { driver.find_element(:accessibility_id, "inputA").displayed? } driver.find_element(:accessibility_id, "inputA").send_keys 5 driver.find_element(:accessibility_id, "inputB").send_keys 10 result = driver.find_element(:accessibility_id, "sum") if (!result.nil?) && (result.text.eql? "15") puts "Test Passed" else puts "Test Failed" end driver.quit require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "17.4", "appium:app" => "https://testingbot.com/appium/sample.zip", "tb:options" => { "name" => "Ruby Appium Example" } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://hub.testingbot.com/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) driver.find_element(:accessibility_id, "inputA").send_keys 5 driver.find_element(:accessibility_id, "inputB").send_keys 10 driver.quit Make sure to always stop your test (`driver.quit`), otherwise it will continue running, leading to a timeout. ## Uploading Your App Please see our [Upload Mobile App](https://testingbot.com/support/app-automate/help/upload) documentation to find out how to upload your app to TestingBot for testing. ## Specify Devices To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote devices. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "http://localhost:4723/wd/hub" }}, true) **After:** appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://hub.testingbot.com/wd/hub" }}, true) To let TestingBot know on which device you want to run your test on, you need to specify the `appium:deviceName`, `appium:platformVersion`, `platformName` and other optional options in the capabilities field. To see how to do this, please select a combination of device type and device name in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.6›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Ruby WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "17.4", "appium:app" => "https://testingbot.com/appium/sample.zip", "tb:options" => { "name" => "single_test", "build" => "Ruby Appium Sample" } } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { # Point to local tunnel instead of hub.testingbot.com server_url: "http://localhost:4445/wd/hub" }}, true) driver = appium_driver.start_driver wait = Selenium::WebDriver::Wait.new(:timeout => 30) driver.find_element(:accessibility_id, "inputA").send_keys 5 driver.find_element(:accessibility_id, "inputB").send_keys 10 driver.quit ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different device configurations or run different tests all on the same device configuration. TestingBot has a large grid of devices, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To get started, please see the examples on [https://github.com/grosser/parallel\_tests](https://github.com/grosser/parallel_tests) ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Preparing your App You do not need to install any code or plugin to run a test. Below are some things that are necessary to successfully run a mobile test: **For Android:** - Please supply the URL to your `.apk` or `.aab` file. **Important:** the `.apk` file needs to be a x86 build (x86 ABI) for Android emulators. **For iOS Real Device:** - Please supply the URL to an `.ipa` file. **For iOS Simulator:** - Please supply the URL to a `.zip` file that contains your `.app` - The `.app` needs to be an iOS Simulator build: - Create a Simulator build: xcodebuild -sdk iphonesimulator -configuration Debug - Zip the `.app` bundle: zip -r MyApp.zip MyApp.app ## Additional Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: `fr_CA`) This sets the locale on the entire device/simulator, except on physical iOS devices. For real iOS devices, we will pass `-AppleLocale` as argument to the app. - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/test-app-upgrades # Test App Upgrades/Mid-Session App Installations As app developers, we frequently release new versions of our applications. In most cases, users upgrade from an older version rather than installing the app from scratch. This transition often requires migrating existing user data to ensure the app functions correctly, making upgrade testing a crucial step in development. By thoroughly testing upgrades, we can confirm that the app continues to work as expected post-update. App upgrades aren't the only scenario where installing apps during a running session is necessary. Some applications may depend on other apps to function properly. If your app interacts with another application—such as pulling data or integrating with its features — it's essential to verify that these dependencies remain intact after an upgrade. Additionally, there are cases where you might need to delete and reinstall an app during a session. For example, if you want to test how the app behaves when a user uninstalls and reinstalls it, the mid-session install feature can facilitate this process. ## (Re-)Installing apps during a test Before you can install a new app, or a new version of the app, we encourage you to first upload your `.apk/.ipa/.zip` file to [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload). Alternatively, you can also specify a URL to an `.apk/.ipa/.zip` file that is publicly accessible. During your test, you can use the `mobile:installApp` command to install the app on the device. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) driver.executeScript("mobile: installApp", ImmutableMap.of("appPath", "tb://.apk|ipa|zip")); await driver.execute('mobile: installApp', {"appPath": "tb://.apk|ipa|zip"}); driver.execute_script('mobile: installApp', {"appPath": "tb://.apk|ipa|zip"}) driver.execute_script('mobile: installApp', {"appPath" => "tb://.apk|ipa|zip"}) driver.ExecuteScript("mobile: installApp", new Dictionary { { "appPath", "tb://.apk|ipa|zip" } }); A successful installation will return the following response, which can be used to validate if the right version of the app was installed: { "packageName": "com.testingbot.com", "version": "2.3.1", "buildNumber": "116" } Appium will not automatically launch the app after you installed it during the test. You can launch the app manually using the following commands after installation: - **Android:** `mobile: startActivity` - **iOS:** `mobile: launchApp` [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) // Android driver.executeScript("mobile: startActivity", ImmutableMap.of("intent", "com.testingbot.demo/.MainActivity")); // iOS driver.executeScript("mobile: launchApp", ImmutableMap.of("bundleId", "com.testingbot.demo")); // Android await driver.execute('mobile: startActivity', {intent: 'com.testingbot.demo/.MainActivity'}); // iOS await driver.execute('mobile: launchApp', {bundleId: 'com.testingbot.demo'}); # Android driver.execute_script("mobile: startActivity", {"intent": "com.testingbot.demo/.MainActivity"}) # iOS driver.execute_script("mobile: launchApp", {"bundleId": "com.testingbot.demo"}) # Android @driver.execute_script("mobile: startActivity", {"intent" => "com.testingbot.demo/.MainActivity"}) # iOS @driver.execute_script("mobile: launchApp", {"bundleId" => "com.testingbot.demo"}) // Android driver.ExecuteScript("mobile: startActivity", new Dictionary { { "intent", "com.testingbot.demo/.MainActivity" } }); // iOS driver.ExecuteScript("mobile: launchApp", new Dictionary { { "bundleId", "com.testingbot.demo" } }); ## Removing your app during a test To remove your app during a test, you can use the [`mobile: removeApp`](https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-removeapp) command. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) // Android driver.executeScript("mobile: removeApp", ImmutableMap.of("appId", "com.testingbot.demo")); // iOS driver.executeScript("mobile: removeApp", ImmutableMap.of("bundleId", "com.testingbot.demo")); // Android await driver.execute('mobile: removeApp', {appId: 'com.testingbot.demo'}); // iOS await driver.execute('mobile: removeApp', {bundleId: 'com.testingbot.demo'}); # Android driver.execute_script("mobile: removeApp", {"appId": "com.testingbot.demo"}) # iOS driver.execute_script("mobile: removeApp", {"bundleId": "com.testingbot.demo"}) # Android @driver.execute_script("mobile: removeApp", {"appId" => "com.testingbot.demo"}) # iOS @driver.execute_script("mobile: removeApp", {"bundleId" => "com.testingbot.demo"}) // Android driver.ExecuteScript("mobile: removeApp", new Dictionary { { "appId", "com.testingbot.demo" } }); // iOS driver.ExecuteScript("mobile: removeApp", new Dictionary { { "bundleId", "com.testingbot.demo" } }); ## Other app commands Appium supports more commands to handle apps during a test, such as: ### mobile: terminateApp This will forcefully stop the app (specified by bundleId or appId) on the device. ### mobile: isAppInstalled Verifies if the app (specified by bundleId or appId) is on the device. Returns a boolean true or false. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/upload-files # Upload files to physical devices TestingBot provides a feature that allows you to specify one or more media files that need to be uploaded to a physical iOS or Android device, prior to running your Appium test. This functionality allows you to run tests that require media files (photos and videos) from the iOS or Android photo gallery. There are two options to use this feature, depending on your usecase. We suggest using the first option, which will use TestingBot's custom `uploadMedia` capability. - [TestingBot Upload Capability](https://testingbot.com#testingbot) - [Appium Push and Pull](https://testingbot.com#appium) ## TestingBot Upload Capability To use this functionality, you can use the `uploadMedia` capability, specifying an array of URLs to image files or video files. You can specify URLs to publicly downloadable media files, or you can use TestingBot Storage to upload the files to TestingBot and use the `tb://` URLs. ### Upload files to TestingBot [cURL](https://testingbot.com#) curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/storage" \ -F "file=@/path/to/app/file/media.png" The API response will include a `tb://` URL, which you can use in the `uploadMedia` capability. { "app_url": "tb://edb4f4f3ed95a4f46714f3df" } Uploads to our TestingBot Storage are automatically deleted after 62 days. ### Add the capability to your Appium script [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) Map tbOptions = new HashMap<>(); tbOptions.put("uploadMedia", new String[]{"tb://edb4f4f3ed95a4f46714f3df"}); options.setCapability("tb:options", tbOptions); const capabilities = { 'tb:options': { 'uploadMedia': ['tb://edb4f4f3ed95a4f46714f3df'] } } capabilities = { "tb:options" : { "uploadMedia" : ["tb://edb4f4f3ed95a4f46714f3df"] } } capabilities = { "tb:options" => { "uploadMedia" => ["tb://edb4f4f3ed95a4f46714f3df"] } } AppiumOptions options = new AppiumOptions(); var tbOptions = new Dictionary(); tbOptions.Add("uploadMedia", new string[] { "tb://edb4f4f3ed95a4f46714f3df" }); options.AddAdditionalAppiumOption("tb:options", tbOptions); TestingBot will add these files to the Android or iOS device. The metadata of the gallery on the device will be updated automatically, which means the media file will immediately appear in the device's gallery. - **Android:** the media files will be added to the Default Gallery app. `/sdcard/Pictures` for images and `/sdcard/Movies` for videos. - **iOS:** the media files will be added to the iOS Camera Roll: `com.apple.mobileslideshow` ## Appium Push and Pull Appium provides both [pushFile](https://appium.io/docs/en/2.0/reference/interfaces/appium_types.ExternalDriver/#pushfile) and [pullFile](https://appium.io/docs/en/2.0/reference/interfaces/appium_types.ExternalDriver/#pullfile) functionality. This is supported since [Appium Version](https://testingbot.com/support/app-automate/appium/options#appiumVersion) 1.15.0. With this approach, the file is pushed when the test has already started. Pushing media files to the iOS or Android device does not guarantee the updating of the metadata in the iOS or Android gallery, which means your media file might not appear (immediately). ### Android Example Push a file to the SD Card of the Android device: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) // Push a file to the sdcard driver.pushFile("/sdcard/Download/sample.png", new File("~/sample.png")); // Pull file from sdcard byte[] fileBase64 = driver.pullFile("/sdcard/Download/sample.png"); // Push file - WebdriverIO syntax const data = Buffer.from("TestingBot").toString('base64'); await driver.pushFile('/sdcard/Download/sample.txt', data); // Pull file WebdriverIO example const fileData = await driver.pullFile('/sdcard/Download/sample.txt'); # Push a file dest_path = '/sdcard/Download/sample.txt' driver.push_file(dest_path, 'TestingBot'.encode("utf-8")) # Pull file file_base64 = driver.pull_file(dest_path) # Push a file driver.push_file('/sdcard/Download/sample.png', File.read('/Users/testingbot/Desktop/sample.png')) # Pull file driver.pull_file('/sdcard/Download/sample.png') // Push a file driver.PushFile("/sdcard/Download/sample.png", new FileInfo("/Users/testingbot/Desktop/sample.png")); // Pull file byte[] fileBase64 = driver.PullFile("/sdcard/Download/sample.png"); ### iOS Example Before using the pull and push functionality, you'll need to ensure that: - Your iOS app must have set the `UIFileSharingEnabled` key to `true` in the `Info.plist` file, which enables file sharing. - Alternatively, you can set the `LSSupportsOpeningDocumentsInPlace` key to `true` in the `Info.plist` to expose your app's folder in the **Files** app on the iOS device. The destination path to push a file is in the following format: `@:documents/.` [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) // Push an image file driver.pushFile("@com.testingbot.Sample-App:documents/sample.png", new File("/Users/testingbot/Desktop/sample.png")); // Pull file byte[] fileBase64 = driver.pullFile("@com.testingbot.Sample-App:documents/sample.png"); // Push file WebdriverIO example const data = Buffer.from("TestingBot").toString('base64'); await driver.pushFile('@com.testingbot.Sample-App:documents/sample.txt', data); // Pull file WebdriverIO example const fileData = await driver.pullFile('@com.testingbot.Sample-App:documents/sample.txt'); # Push an image file driver.push_file('@com.testingbot.Sample-App:documents/sample.png', source_path='/Users/testingbot/Desktop/sample.png') # Push a text file dest_path = '@com.testingbot.Sample-App:documents/sample.txt' driver.push_file(dest_path, 'TestingBot'.encode("utf-8")) # Pull file file_base64 = driver.pull_file(dest_path) # Push an image file driver.push_file('@com.testingbot.Sample-App:documents/sample.png', File.read('/Users/testingbot/Desktop/sample.png')) # Pull file driver.pull_file('@com.testingbot.Sample-App:documents/image.png') // Push an image file driver.PushFile("@com.testingbot.Sample-App:documents/image.jpg", new FileInfo("/Users/testingbot/Desktop/sample.png")) // Pull file byte[] fileBase64 = driver.PullFile("@com.testingbot.Sample-App:documents/sample.png"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/permission-popups # Handling permission pop-ups While testing your mobile app, it may ask for specific permissions during the test. Various system dialogs or popups may appear, asking the user to grant access. The mobile app might ask the user permission to access the contacts, notifications, media, ... on the device. Below we'll go over the various techniques to handle these events during your mobile testing: - [Allow or Deny all permissions](https://testingbot.com#allPermissions) - [Allow or Deny specific permissions](https://testingbot.com#specificPermissions) ## Allow or Deny all permissions Appium allows you to automatically accept all permission and alert requests. ### Allow or Deny all permissions on Android You can use the `autoGrantPermissions` capability. Appium will inspect the [Android Manifest](https://developer.android.com/guide/topics/manifest/manifest-intro) of the app, extract the required permissions and grant these. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps["appium:autoGrantPermissions"] = true options.setCapability("appium:autoGrantPermissions", true); capabilities = { "appium:autoGrantPermissions": True } const capabilities = { "appium:autoGrantPermissions": true } options.AddAdditionalAppiumOption("appium:autoGrantPermissions", true); ### Allow or Deny all permissions on iOS On iOS, Appium offers two capabilities which you can use: `autoAcceptAlerts` and `autoDismissAlerts`. `autoAcceptAlerts` will automatically accept (grant) any alerts (including permission popups) that might appear during your test. `autoDismissAlerts` will automatically dismiss (deny) any alerts (including permission popups) that might appear during your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps["appium:autoAcceptAlerts"] = true # to accept all alerts caps["appium:autoDismissAlerts"] = true # to dismiss all alerts options.setCapability("appium:autoAcceptAlerts", true); // to accept all alerts options.setCapability("appium:autoDismissAlerts", true); // to dismiss all alerts capabilities = { "appium:autoAcceptAlerts": True # to accept all alerts } capabilities = { "appium:autoDismissAlerts": True # to dismiss all alerts } const capabilities = { "appium:autoAcceptAlerts": true // to accept all alerts } const capabilities = { "appium:autoDismissAlerts": true // to dismiss all alerts } options.AddAdditionalAppiumOption("appium:autoAcceptAlerts", true); // to accept all alerts options.AddAdditionalAppiumOption("appium:autoDismissAlerts", true); // to dismiss all alerts ### Customizing the alert button selector There may be dialogs that appear during your automated tests which have 3 buttons instead of 2, or there's a specific button you want to press instead of the default (allow) button. In this case, you might want to consider using the `acceptAlertButtonSelector` Appium setting, which allows you to pass a selector (a [class-chain expression](https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules)) to tell Appium which button to click. For example, you might want to click the 'Allow Once' button in a location permission dialog. To instruct Appium to do this, you can change the `acceptAlertButtonSelector` setting during your test: driver.updateSettings({ acceptAlertButtonSelector: "**/XCUIElementTypeButton[`label CONTAINS[c] 'Allow Once'`]" }); Alternatively, you can set this setting at the beginning of your test with a capability: const capabilities = { "appium:settings[acceptAlertButtonSelector]": "**/XCUIElementTypeButton[`label CONTAINS[c] 'Allow Once'`]" } ## Allow or Deny specific permissions You can also choose to accept or deny alerts and popups during your test. Your test will need to find the element of the alert or popup and perform a `click` action on that element. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) # For Android driver.find_element(:xpath, ".//android.widget.Button[@text='Allow']").click # For iOS driver.find_element(:id, "Allow").click // For Android driver.findElement(By.xpath(".//android.widget.Button[@text='Allow']")).click(); // For iOS driver.findElement(By.id("Allow")).click(); from selenium.webdriver.common.by import By # For Android driver.find_element(By.XPATH, ".//android.widget.Button[@text='Allow']").click() # For iOS driver.find_element(By.ID, "Allow").click() // For Android const element = await driver.$(".//android.widget.Button[@text='Allow']"); await element.click(); // For iOS const allowBtn = await driver.$("#Allow"); await allowBtn.click(); // For Android IWebElement ll = driver.FindElement(By.XPath(".//android.widget.Button[@text='Allow']")); ll.Click(); // For iOS IWebElement ll = driver.FindElement(By.Id("Allow")); ll.Click(); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/screen-orientation # Change screen orientation Appium allows you to change the screen orientation of your iOS and Android devices. You can choose to either change the orientation [at the start of the test](https://testingbot.com#caps) or [during a test](https://testingbot.com#during). ## Set screen orientation at the start of your test [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[Node](https://testingbot.com#)[C#](https://testingbot.com#) capabilities = { "appium:orientation" => "LANDSCAPE" } options.setCapability("appium:orientation", "LANDSCAPE"); $capabilities = [ "appium:orientation" => "LANDSCAPE" ]; capabilities = { "appium:orientation": "LANDSCAPE" } const capabilities = { "appium:orientation": "LANDSCAPE" }; options.AddAdditionalAppiumOption("appium:orientation", "LANDSCAPE"); ## Set screen orientation during a test [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[Node](https://testingbot.com#)[C#](https://testingbot.com#) @driver.rotation = :landscape ((AppiumDriver) driver).rotate(ScreenOrientation.LANDSCAPE); $driver->rotate("LANDSCAPE"); driver.orientation = "LANDSCAPE" await driver.setOrientation('landscape'); driver.Orientation = ScreenOrientation.Landscape; Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/localization-options # Localization testing on iOS and Android When running tests with Appium, you can choose to set a specific locale for the device or emulator, by using the `appium:locale` capability. Specifying this capability will make sure the device/emulator and app will display or format data such as dates, time, decimal separators and calendars according to the specified country's regional conventions. On iOS, you can use a locale format such as `fr_CA` to indicate you want the french region in Canada. More information is available in the [Locale IDs documentation](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15-SW9). You can also change the Simulator UI locale at runtime using the following script command: `mobile: configureLocalization`. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) capabilities = { "appium:locale" => "ES" } options.setCapability("appium:locale", "ES"); $capabilities = [ "appium:locale" => "ES" ]; capabilities = { "appium:locale": "ES" } const capabilities = { "appium:locale": "ES" }; options.AddAdditionalAppiumOption("appium:locale", "ES"); ### Android locale codes | Locale | Locale Code | | --- | --- | | Australia | AU | | Austria | AT | | Belgium | BE | | Brazil | BR | | Britain | GB | | Bulgaria | BG | | Canada | CA | | Croatia | HR | | Czech Republic | CZ | | Denmark | DK | | Egypt | EG | | Finland | FI | | France | FR | | Germany | DE | | Greece | GR | | Hong-Kong | HK | | Hungary | HU | | India | IN | | Indonesia | ID | | Ireland | IE | | Israel | IL | | Italy | IT | | Japan | JP | | Korea | KR | | Latvia | LV | | Liechtenstein | LI | | Lithuania | LT | | Mexico | MX | | Netherlands | NL | | New Zealand | NZ | | Norway | NO | | Philippines | PH | | Poland | PL | | Portugal | PT | | PRC | CN | | Romania | RO | | Russia | RU | | Serbia | RS | | Singapore | SG | | Slovakia | SK | | Slovenia | SI | | Spain | ES | | Sweden | SE | | Switzerland | CH | | Taiwan | TW | | Thailand | TH | | Turkey | TR | | Ukraine | UA | | US | US | | USA | US | | Vietnam | VN | | Zimbabwe | ZW | ### iOS locale codes | Locale | Locale Code | | --- | --- | | Australia  | en\_AU | | Belgium  | nl\_BE | | Belgium  | fr\_BE | | Brunei Darussalam | ms\_BN | | Canada  | en\_CA | | Canada | fr\_CA | | Czech Republic  | cs\_CZ | | Finland | fi\_FI | | Germany  | de\_DE | | Greece | el\_GR | | Hungary | hu\_HU | | India | hi\_IN | | Indonesia | id\_ID | | Israel | he\_IL | | Italy | it\_IT | | Japan | ja\_JP | | Malaysia | ms\_MY | | Netherlands  | nl\_NL | | New Zealand   | en\_NZ | | Norway | nb\_NO | | Philippines  | tl\_PH | | Poland | pl\_PL | | PRC  | zh\_CN | | Romania | ro\_RO | | Russia | ru\_RU | | Singapore | en\_SG | | Slovakia | sk\_SK | | Korea | ko\_KR | | Sweden  | sv\_SE | | Taiwan  | zh\_TW | | Thailand  | th\_TH | | Turkey  | tr\_TR | | UK  | en\_GB | | Ukraine  | uk\_UA | | US | es\_US | | USA | en\_US | | Vietnam  | vi\_VN | | Brazil | pt-BR | | China (Simplified) | zh-Hans | | China (Traditional) | zh-Hant | | Hong Kong | zh-HK | | India | en-IN | | Ireland | en-IE | | Latin America | es-419 | | Mexico | es-MX | | South Africa | en-ZA | ## Change Language Specify the `appium:language` capability to set the language of the app under test, and the device/emulator. On iOS, you can set the language to for example French: `fr`. More information is available in the [Language IDs documentation](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html). You can also change the Simulator UI language at runtime using the following script command: `mobile: configureLocalization`. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) capabilities = { "appium:language" => "es" } options.setCapability("appium:language", "es"); $capabilities = [ "appium:language" => "es" ]; capabilities = { "appium:language": "es" } const capabilities = { "appium:language": "es" }; options.AddAdditionalAppiumOption("appium:language", "es"); ### Android language codes | Language | Language Code | | --- | --- | | Arabic | ar | | Bulgarian | bg | | Catalan | ca | | Chinese | zh | | Croatian | hr | | Czech | cs | | Danish | da | | Dutch | nl | | English | en | | Finnish | fi | | French | fr | | German | de | | Greek | el | | Hebrew | he | | Hindi | hi | | Hungarian | hu | | Indonesian | id | | Italian | it | | Japanese | ja | | Korean | ko | | Latvian | lv | | Lithuanian | lt | | Norwegian-Bokmol | nb | | Polish | pl | | Portuguese | pt | | Romanian | ro | | Russian | ru | | Serbian | sr | | Slovak | sk | | Slovenian | sl | | Spanish | es | | Swedish | sv | | Tagalog | tl | | Thai | th | | Turkish | tr | | Ukrainian | uk | | Vietnamese | vi | ### iOS language codes | Language | Language Code | | --- | --- | | Chinese | zh | | Czech | cs | | Dutch | nl | | English | en | | Finnish | fi | | French | fr | | German | de | | Greek | el | | Hebrew | he | | Hindi | hi | | Hungarian | hu | | Indonesian | id | | Italian | it | | Japanese | ja | | Korean | ko | | Malay | ms | | Norwegian (Bokmal) | nb | | Polish | pl | | Portuguese (Brazil) | pt | | Romanian | ro | | Russian | ru | | Slovak | sk | | Spanish | es | | Swedish | sv | | Tagalog | tl | | Thai | th | | Turkish | tr | | Ukrainian | uk | | Vietnamese | vi | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/dark-mode # Dark Mode testing with Appium Dark mode is a setting, available on both Android and iOS, which toggles the interface appearance of the phone to use either the standard light mode setting or a dark mode. When dark mode is enabled, the phone will switch to a dark background with lighter foreground colors, which enables better viewing in low-light conditions. ## Changing Dark Mode This example will use `mobile: setAppearance` to set the appearance to dark (dark mode). [Android](https://testingbot.com#)[iOS](https://testingbot.com#) const { remote } = require('webdriverio'); const capabilities = { 'platformName': 'Android', 'appium:app': 'https://testingbot.com/appium/sample.apk', 'appium:deviceName': 'Pixel 8', 'appium:platformVersion': '14.0', 'appium:automationName': 'UiAutomator2', 'tb:options': { 'name': 'Dark Mode Test', 'realDevice': true } }; const driver = await remote({ hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: 'api_key', key: 'api_secret', capabilities }); // Enable dark mode await driver.execute('mobile: setAppearance', { style: 'dark' }); const inputA = await driver.$('~inputA'); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.setValue('5'); const sum = await driver.$('~sum'); const value = await sum.getText(); console.assert(value === '15', 'Sum should be 15'); await driver.deleteSession(); Make sure to always stop your test (`driver.deleteSession()`), otherwise it will continue running, leading to a timeout. const { remote } = require('webdriverio'); const capabilities = { 'platformName': 'iOS', 'appium:app': 'https://testingbot.com/appium/sample.ipa', 'appium:deviceName': 'iPhone 15', 'appium:platformVersion': '17.0', 'appium:automationName': 'XCUITest', 'tb:options': { 'name': 'Dark Mode Test', 'realDevice': true } }; const driver = await remote({ hostname: 'hub.testingbot.com', port: 443, protocol: 'https', path: '/wd/hub', user: 'api_key', key: 'api_secret', capabilities }); // Enable dark mode await driver.execute('mobile: setAppearance', { style: 'dark' }); const inputA = await driver.$('~inputA'); await inputA.setValue('10'); const inputB = await driver.$('~inputB'); await inputB.setValue('5'); await driver.deleteSession(); Make sure to always stop your test (`driver.deleteSession()`), otherwise it will continue running, leading to a timeout. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/options # Mobile App Options Please see the examples below on how to customize your test run on our mobile emulators and devices. The [Appium Capabilities generator](https://testingbot.com/support/app-automate/appium/capabilities) allows you to easily generate the necessary capabilities for your mobile tests. ## Appium Options Appium provides [a lot of options](https://appium.io/docs/en/2.0/guides/caps/) to configure your test. Some important options that might help: **For Android:** - **appActivity** and **appPackage** : by default, Appium will try to extract the main Activity from your apk. If this fails, you can supply your own with these options. - **chromeOptions** : additional chromedriver options you can supply. - **otherApps** : a JSON array of other apps that need to be installed, in URL format. **For Android & iOS:** - **locale** : the language of the simulator/device (ex: fr\_CA) - **newCommandTimeout** : How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session ## Specifying Appium Version TestingBot will use the most recent, compatible, Appium version according to the device, OS and version you specify. If you'd like to specify your own Appium version, you can do this with the `appiumVersion` capability. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["appiumVersion"] = "2.0" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("appiumVersion", "2.0"); $caps = array( "appiumVersion" => "2.0" ); capabilities = { "appiumVersion" : "2.0" } const capabilities = { "appiumVersion" : "2.0" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("appiumVersion", "2.0"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "iOS", deviceName: "iPhone 13", browserVersion: "16.0", app: 'https://testingbot.com/appium/sample.ipa', "tb:options" => { "appiumVersion" : "2.0" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("appiumVersion", "2.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "iOS"); caps.setCapability("tb:options", tbOptions); caps.setCapability("deviceName", "iPhone 13"); caps.setCapability("browserVersion", "16.0"); caps.setCapability("app", "https://testingbot.com/appium/sample.ipa"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::safari(); $capabilities->setPlatform('iOS'); $capabilities->setCapability('tb:options', array( 'appiumVersion' => "2.0" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'appiumVersion': "2.0" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.ipa", 'platformName': "iOS", 'browserVersion': "16.0", 'deviceName': "iPhone 13", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.ipa', "platformName": 'iOS', "deviceName": 'iPhone 13', "version": '16.0', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "appiumVersion": "2.0" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "16.0", PlatformName = "iOS", DeviceName = "iPhone 13", App = "https://testingbot.com/appium/sample.ipa", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["appiumVersion"] = "2.0" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Appium 2 Versions We currently support these Appium 2 versions: - 2.11.3 - 2.10.3 - 2.9.0 - 2.5.1 - 2.4.1 - 2.3.0 - 2.2.1 If you specify `"appiumVersion": "latest"`, TestingBot will automatically use the latest Appium version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions of Appium. ## Change Device Timezone TestingBot allows you to change the timezone of the mobile device (physical or emu/sim) to a timezone that you specify. Simply pass in a `timeZone` capability specifying a timezone from the list. You can find a [list of timezones on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["timeZone"] = "Etc/UTC" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("timeZone", "Etc/UTC"); $caps = array( "timeZone" => "Etc/UTC" ); capabilities = { "timeZone" : "Etc/UTC" } const capabilities = { "timeZone" : "Etc/UTC" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("timeZone", "Etc/UTC"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: 'Galaxy S23', "tb:options" => { "timeZone" : "Etc/UTC" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("timeZone", "Etc/UTC"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'timeZone' => "Etc/UTC" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'timeZone': "Etc/UTC" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "timeZone": "Etc/UTC" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var appiumOptions = new AppiumOptions(); appiumOptions.PlatformName = "Android"; appiumOptions.AddAdditionalAppiumOption("appium:app", "https://testingbot.com/appium/sample.apk"); var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["timeZone"] = "Etc/UTC" }; appiumOptions.AddAdditionalAppiumOption("tb:options", tbOptions); chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value | Possible Values: || string | "Etc/UTC" | [List of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | ### Localization Options Please see the [Localization Options documentation](https://testingbot.com/support/app-automate/appium/localization-options) to learn how to set the locale and language of the device during your automated tests. ### Geolocation Testing TestingBot provides an option where you can specify from which country you'd like to run the test from. Once you specify this option, the device we provision for your test will be configured to use a proxy in the country you specified. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["testingbot.geoCountryCode"] = "DE" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("testingbot.geoCountryCode", "DE"); $caps = array( "testingbot.geoCountryCode" => "DE" ); capabilities = { "testingbot.geoCountryCode" : "DE" } const capabilities = { "testingbot.geoCountryCode" : "DE" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("testingbot.geoCountryCode", "DE"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", deviceName: "Galaxy S23", version: "13.0", "tb:options" => { "testingbot.geoCountryCode" : "DE" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("testingbot.geoCountryCode", "DE"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'testingbot.geoCountryCode' => "DE" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'testingbot.geoCountryCode': "DE" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "testingbot.geoCountryCode": "DE" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["testingbot.geoCountryCode"] = "DE" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Specify `testingbot.geoCountryCode` with one of the following country codes: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States **Important:** this does not work on Android 4.4 ## Upload files to device You can upload files to the remote iOS or Android device, prior to starting a test. More information is available on this page: [upload files to device](https://testingbot.com/support/app-automate/appium/upload-files). ## Throttle Network TestingBot provides a throttle network feature, which will simulate specific network conditions during a test. We offer various presets: - **Edge** : - 250kbps download - 150kbps upload - 0% Loss - 300ms Latency - **3G** : - 400kbps download - 100kbps upload - 0% Loss - 100ms Latency - **4G** : - 18000kbps download - 9000kbps upload - 0% Loss - 100ms Latency - **airplane** : Simulates Airplane Mode (no network connectivity) - **disable** : Revert the throttling to no throttling. We also offer the possibility to specify your own `download`, `upload`, `loss` and `latency` values. You can pass a preset or specific options at the start of your test (through the `capabilities`), or during the test (with `execute_script`). **At the start of a test:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { throttle_network: "3G", throttle_network: { uploadSpeed: 10 * 1024, downloadSpeed: 10 * 1024, latency: 0, loss: 0 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("throttle_network", "3G"); MutableCapabilities throttleOptions = new MutableCapabilities(); throttleOptions.setCapability("uploadSpeed", 10 * 1024); throttleOptions.setCapability("downloadSpeed", 10 * 1024); throttleOptions.setCapability("latency", 0); throttleOptions.setCapability("loss", 0); tbOptions.setCapability("throttle_network", throttleOptions); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'throttle_network' => '3G', 'throttle_network' => array( 'uploadSpeed' => 10 * 1024, 'downloadSpeed' => 10 * 1024, 'latency' => 0, 'loss' => 0 ) )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'throttle_network': '3G', 'throttle_network': { 'uploadSpeed': 10 * 1024, 'downloadSpeed': 10 * 1024, 'latency': 0, 'loss': 0 } } chromeOpts = { 'browserName': "chrome", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "throttle_network": "3G", "throttle_network": { "uploadSpeed": 10 * 1024, "downloadSpeed": 10 * 1024, "latency": 0, "loss": 0 } } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var appiumOptions = new AppiumOptions(); appiumOptions.PlatformName = "Android"; appiumOptions.AddAdditionalAppiumOption("appium:app", "https://testingbot.com/appium/sample.apk"); var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["throttle_network"] = "3G" }; appiumOptions.AddAdditionalAppiumOption("tb:options", tbOptions); var driver = new AndroidDriver(new Uri("https://hub.testingbot.com/wd/hub"), appiumOptions, TimeSpan.FromSeconds(600)); **During a test:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script("tb:throttle", "3G") # or driver.execute_script("tb:throttle", { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }) ((JavascriptExecutor) driver).executeScript("tb:throttle", "3G"); // or Map throttleMap = new HashMap<>(); throttleMap.put("downloadSpeed", 10 * 1024); throttleMap.put("uploadSpeed", 10 * 1024); throttleMap.put("latency", 0); throttleMap.put("loss", 0); ((JavascriptExecutor) driver).executeScript("tb:throttle", throttleMap); $driver->executeScript("tb:throttle", ["3G"]); // or $driver->executeScript("tb:throttle", [ "downloadSpeed" => 10 * 1024, "uploadSpeed" => 10 * 1024, "latency" => 0, "loss" => 0 ]); driver.execute_script("tb:throttle", "3G") # or driver.execute_script("tb:throttle", { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }) browser.execute('tb:throttle', '3G') // or browser.execute('tb:throttle', { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }) ((IJavaScriptExecutor)driver).ExecuteScript("tb:throttle", "3G"); // or ((IJavaScriptExecutor)driver).ExecuteScript("tb:throttle", "{\"downloadSpeed\":10*1024, \"uploadSpeed\": 10*1024, \"latency\": 0, \"loss\": 0}"); To stop network throttling during your test, pass `disable: true` in the `tb:throttle` options via the `execute_script`. ## mobile: shell You can execute ADB shell commands during your automated test, with Appium's `mobile: shell` functionality. This allows you to fetch or set various settings for the device or emulator, during your automated test. For example, send a custom `input` event, or use `dumpsys`, `pm clear` or others. When running a test on an emulator, all ADB shell commands are allowed. For tests running on physical devices, we maintain a whitelist of allowed commands **Whitelisted ADB commands for physical devices** : - am start - am force-stop - pm clear - input - (ls|cp|mkdir|echo|grep|cut|pwd|dumpsys) - getprop - am compat enable - cmd connectivity airplane-mode (enable|disable) - settings put global (animator\_duration\_scale|transition\_animation\_scale|window\_animation\_scale) \ - setprop debug.firebase.analytics.app \ - setprop (log.tag.FA|log.tag.FA-SVC) (ERROR|WARN|INFO|DEBUG|VERBOSE) - setprop (log.tag.FA|log.tag.FA-SVC|log.tag.GAv4|log.tag.GAv4-SVC) (ERROR|WARN|INFO|DEBUG|VERBOSE) - appops set \ REQUEST\_INSTALL\_PACKAGES allow [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script('mobile: shell', { command: 'input', args: ['keyevent', 3] }) driver.executeScript("mobile: shell", ImmutableMap.of( "command", "input", "args", ImmutableList.of("keyevent", "3") )); $args = [ "command" => "input", "args" => ["keyevent", "3"] ]; $driver->executeScript("mobile: shell", $args); args = { "command": "input", "args": ["keyevent", "3"] } driver.execute_script("mobile: shell", args) await driver.executeScript("mobile: shell", { command: "input", args: ["keyevent", "3"] }); var args = new Dictionary { { "command", "input" }, { "args", new List { "keyevent", "3" } } }; ((IJavaScriptExecutor)driver).ExecuteScript("mobile: shell", args); ### Device Name When running a mobile automated test, you'll need to specify on which [mobile device](https://testingbot.com/support/app-automate/devices) (or [simulator/emulator](https://testingbot.com/support/web-automate/browsers)) you want to test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "Samsung S21" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("deviceName", "Samsung S21"); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "Samsung S21", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "deviceName": 'Samsung S21', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "Samsung S21" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Physical Devices Only We offer special parameters which you can use to allocate a device: Regex Input | Result || `"iPhone.*"` | This will allocate any available iPhone device (phone) | | `".*Galaxy.*"` | This will allocate any of the available Galaxy devices (phone or tablet) | | `"*"` | This will allocate a random available device, either iOS or Android device | | `"iPhone [8-11]"` | This will allocate either an iPhone 8 or 11 | | `"iPhone 6.*"` | This will allocate either an iPhone 6 or 6S | Some Examples: // find any iPhone, except 6 or 6s capabilities.setCapability("deviceName", "^(iPhone.*)(?!6|6S)$"); // find any device which name starts with Samsung capabilities.setCapability("deviceName", "Samsung.*"); ### Device Version You can specify the version of the device you want to target. In case of physical devices, you might want to use regex/wildcard patterns to target a broad range of devices. This way your chance of hitting an occupied device during your automated test decreases significantly. Instead of only targetting a specific iOS or Android device, you can target a wider range of devices. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { version: "(16|17).*" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("appium:platformName", "Android"); caps.setCapability("appium:deviceName", "*"); caps.setCapability("tb:options", tbOptions); caps.setCapability("appium:version", "(13|14).*"); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'appium:deviceName': "*", 'appium:version': '(13|14).*', 'platformName': "Android", 'goog:chromeOptions': {'w3c': True} } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "appium:deviceName": '*', "appium:version": '(13|14).*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android" }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*", ["version"] = "(13|14).*" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Some Examples: // target multiple specific versions of an iPhone device capabilities.setCapability("appium:deviceName", "iPhone.*"); capabilities.setCapability("appium:version", "18.0|15.0|14.2|14"); // find any Samsung device with Android version 13 or 14 capabilities.setCapability("appium:deviceName", "Samsung.*"); capabilities.setCapability("appium:version", "(13|14).*"); ### Tablet Only You can specify this capability when you only want to allocate a tablet device. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "*", tabletOnly: true } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("tabletOnly", true); tbOptions.setCapability("deviceName", "*"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "*", 'tabletOnly': true, 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "deviceName": '*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "tabletOnly": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*", ["tabletOnly"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Phone Only You can specify this capability when you only want to allocate a phone device. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "*", phoneOnly: true } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("phoneOnly", true); tbOptions.setCapability("deviceName", "*"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "*", 'phoneOnly': true, 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "deviceName": '*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "phoneOnly": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*", ["phoneOnly"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Change Test Name Add a name to this test, which will show up in the TestingBot member area and API. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["name"] = "My Test Name" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("name", "My Test Name"); $caps = array( "name" => "My Test Name" ); capabilities = { "name" : "My Test Name" } const capabilities = { "name" : "My Test Name" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("name", "My Test Name"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "name" : "My Test Name" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("name", "My Test Name"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'name' => "My Test Name" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': "My Test Name" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'deviceName': "Galaxy S23", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "name": "My Test Name" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "My Test Name" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || string | unnamed test | ### Group Tests A key you can use to group certain tests in the same build (for example in Jenkins). The builds will appear in our member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["build"] = "My First Build" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("build", "My First Build"); $caps = array( "build" => "My First Build" ); capabilities = { "build" : "My First Build" } const capabilities = { "build" : "My First Build" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("build", "My First Build"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "build" : "My First Build" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("build", "My First Build"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'build' => "My First Build" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'build': "My First Build" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'deviceName': "Galaxy S23", 'version': '13.0', 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "build": "My First Build" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["build"] = "My First Build" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type || string | ### Idle Timeout The maximum amount of time a device will wait before proceeding to the next step in your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["idletimeout"] = 130 DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("idletimeout", 130); $caps = array( "idletimeout" => 130 ); capabilities = { "idletimeout" : 130 } const capabilities = { "idletimeout" : 130 } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("idletimeout", 130); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "idletimeout" : 130 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("idletimeout", 130); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'idletimeout' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'idletimeout': 130 } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "idletimeout": 130 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["idletimeout"] = 130 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || int (specify number of seconds) | 130 seconds | ### Maximum Test Duration The maximum duration for a single test. This is a safeguard to prevent bad tests from using up your credits. We generally recommend to keep tests short (less than 10 minutes). It's better to split up large tests in smaller individual tests. This keeps your tests fast and allows for more parallelization of your tests. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["maxduration"] = 1800 DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("maxduration", 1800); $caps = array( "maxduration" => 1800 ); capabilities = { "maxduration" : 1800 } const capabilities = { "maxduration" : 1800 } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("maxduration", 1800); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "maxduration" : 1800 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("maxduration", 1800); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'maxduration' => 1800 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'maxduration': 1800 } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "maxduration": 1800 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["maxduration"] = 1800 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || int (specify number of seconds) | 1800 seconds (30 minutes) | ### Custom Metadata Send along custom data, for example your release, server, commit hash, ... This will show up on the test detail page in the TestingBot member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["extra"] = "Extra Information" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("extra", "Extra Information"); $caps = array( "extra" => "Extra Information" ); capabilities = { "extra" : "Extra Information" } const capabilities = { "extra" : "Extra Information" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("extra", "Extra Information"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "extra" : "Extra Information" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("extra", "Extra Information"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'extra' => "Extra Information" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'extra': "Extra Information" } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "extra": "Extra Information" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["extra"] = "Extra Information" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type || string | ### Taking screenshots during your tests By default, TestingBot does not capture screenshots at every step of your mobile test. If you wish to take a screenshot for every step, please add this capability (set to `true`) to your request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screenshot"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screenshot", true); $caps = array( "screenshot" => true ); capabilities = { "screenshot" : True } const capabilities = { "screenshot" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screenshot", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { screenshot: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenshot", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'screenshot' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenshot': True } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk, 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenshot": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "23", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenshot"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | false | ### Make a video of your tests By default we record a video of your test, which is accessible in the member area. If you do not wish to have this, you can disable it with this option. Video should not slow down your test considerably. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screenrecorder"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screenrecorder", true); $caps = array( "screenrecorder" => true ); capabilities = { "screenrecorder" : True } const capabilities = { "screenrecorder" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screenrecorder", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", "tb:options" => { screenrecorder: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenrecorder", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'screenrecorder' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenrecorder': True } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenrecorder": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenrecorder"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | true | ### Test Privacy Make the test results for this test public so that everyone can access the results. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["public"] = false DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("public", false); $caps = array( "public" => false ); capabilities = { "public" : False } const capabilities = { "public" : false } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("public", false); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", "tb:options" => { "public" : false } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("public", false); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'public' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'public': False } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "public": false } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["public"] = false }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value || boolean | false | ### Customize Logging By default, TestingBot records logs of all test actions and its drivers. Set this option to `false` if you don't want TestingBot to record anything (for example, if you have sensitive data). You will not see any test logs in our member dashboard. Set to `strip-parameters` to prevent the POST/GET parameters from being logged on the TestingBot test detail page (does not affect other logs like Appium logs, Chromedriver logs, ...). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["recordLogs"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("recordLogs", true); $caps = array( "recordLogs" => true ); capabilities = { "recordLogs" : True } const capabilities = { "recordLogs" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("recordLogs", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Android", app: "https://testingbot.com/appium/sample.apk", version: "13.0", deviceName: "Galaxy S23", "tb:options" => { "recordLogs" : true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("recordLogs", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("app", "https://testingbot.com/appium/sample.apk"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Android'); $capabilities->setCapability('tb:options', array( 'recordLogs' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'recordLogs': True } chromeOpts = { 'app': "https://testingbot.com/appium/sample.apk", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "app": 'https://testingbot.com/appium/sample.apk', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "recordLogs": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { Version = "13.0", PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["recordLogs"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Value Type | Default Value | Possible Values: || string | "true" | `true`, `false`, or `strip-parameters` | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/appium/instrumentation # App Instrumentation with Appium App instrumentation means adding extra hooks to your app while it runs on TestingBot's devices. It lets your automated tests interact with things that normally require human interaction, such as authentication, taking a specific photo or making a call. With app instrumentation, you can perform the following tasks in an automated Appium test script: - [Inject images into the camera](https://testingbot.com#image-injection): feed a test image to the virtual camera instead of using a real one. - [Biometric authentication](https://testingbot.com#biometric): simulate fingerprint or Touch ID prompts in your tests. - [Receive calls and SMS messages](https://testingbot.com#calls-sms): emulate incoming phone calls or text messages to see how your app responds. ## Injecting images into camera Android Emulators Only Image injection allows you to specify a base64 encoded image to the virtual camera of the Android emulator. The test script will fetch the content of the image, convert it to base64 and send it to the TestingBot grid. The image will be used by the remote device to inject into the camera. Make sure to include the `images` Appium plugin, as it is required for this to function correctly. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.AppiumDriver; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; import java.util.Base64; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; public class ImageInjectionExample { public static String imageToBase64(String url) throws Exception { byte[] data = java.net.URI.create(url).toURL().openStream().readAllBytes(); return Base64.getEncoder().encodeToString(data); } public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platformName", "Android"); caps.setCapability("browserName", "chrome"); caps.setCapability("browserVersion", "15"); caps.setCapability("appium:deviceName", "Pixel 9"); caps.setCapability("tb:appiumPlugins", new String[]{"images"}); caps.setCapability("tb:appiumVersion", "2.11.3"); caps.setCapability("appium:injectedImageProperties", new HashMap<>()); AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps); String base64Image = imageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png"); driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap() {{ put("payload", base64Image); }}); Thread.sleep(30000); base64Image = imageToBase64("https://testingbot.com/assets/about.png"); driver.executeScript("mobile: injectEmulatorCameraImage", new HashMap() {{ put("payload", base64Image); }}); Thread.sleep(30000); driver.quit(); } } const { remote } = require('webdriverio'); const fs = require('fs'); const fetch = require('node-fetch'); async function imageToBase64(url) { const res = await fetch(url); const buffer = await res.buffer(); return buffer.toString('base64'); } (async () => { const caps = { platformName: 'Android', 'appium:deviceName': 'Pixel 9', browserName: 'chrome', browserVersion: '15', 'tb:appiumPlugins': ['images'], 'tb:appiumVersion': '2.11.3', 'appium:injectedImageProperties': {} }; const driver = await remote({ protocol: 'https', hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', user: 'key', key: 'secret', capabilities: caps }); let base64Image = await imageToBase64('https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png'); await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]); console.log("Injected first image"); await driver.pause(30000); base64Image = await imageToBase64('https://testingbot.com/assets/about.png'); await driver.executeScript('mobile: injectEmulatorCameraImage', [{ payload: base64Image }]); console.log("Injected second image"); await driver.pause(30000); await driver.deleteSession(); })(); from appium import webdriver import base64 import requests import time def image_to_base64(url): response = requests.get(url) return base64.b64encode(response.content).decode('utf-8') caps = { "platformName": "Android", "browserName": "chrome", "browserVersion": "15", "appium:deviceName": "Pixel 9", "tb:appiumPlugins": ["images"], "tb:appiumVersion": "2.11.3", "appium:injectedImageProperties": {} } driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps) base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png") driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image }) time.sleep(30) print("Changing image") base64_image = image_to_base64("https://testingbot.com/assets/about.png") driver.execute_script("mobile: injectEmulatorCameraImage", { "payload": base64_image }) time.sleep(30) driver.quit() #!/usr/bin/env ruby require 'rubygems' require 'appium_lib' require 'base64' require 'open-uri' def image_to_base64(image_url) image_data = URI.parse(image_url).open.read Base64.strict_encode64(image_data) end caps = { "browserName" => "chrome", "browserVersion" => "15", "appium:deviceName" => "Pixel 9", "platformName" => "Android", "tb:appiumPlugins" => ["images"], "tb:appiumVersion" => "2.11.3", "appium:injectedImageProperties" => {} } appium_driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://key:secret@hub.testingbot.com/wd/hub" } }, true) driver = appium_driver.start_driver base64_image = image_to_base64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png") driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image }) sleep 30 puts "Changing image" base64_image = image_to_base64("https://testingbot.com/assets/about.png") driver.execute_script('mobile: injectEmulatorCameraImage', { payload: base64_image }) sleep 30 driver.quit using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Remote; using System; using System.Net.Http; using System.Threading.Tasks; class ImageInjectionExample { static async Task ImageToBase64(string url) { using (HttpClient client = new HttpClient()) { var data = await client.GetByteArrayAsync(url); return Convert.ToBase64String(data); } } static async Task Main(string[] args) { var options = new AppiumOptions(); options.PlatformName = "Android"; options.AddAdditionalAppiumOption("browserName", "chrome"); options.AddAdditionalAppiumOption("browserVersion", "15"); options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9"); options.AddAdditionalAppiumOption("tb:appiumPlugins", new string[] { "images" }); options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3"); options.AddAdditionalAppiumOption("appium:injectedImageProperties", new { }); var driver = new RemoteWebDriver( new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options ); var base64Image = await ImageToBase64("https://upload.wikimedia.org/wikipedia/commons/5/5e/QR_Code_example.png"); driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary { { "payload", base64Image } }); Console.WriteLine("Injected first image"); System.Threading.Thread.Sleep(30000); base64Image = await ImageToBase64("https://testingbot.com/assets/about.png"); driver.ExecuteScript("mobile: injectEmulatorCameraImage", new Dictionary { { "payload", base64Image } }); Console.WriteLine("Injected second image"); System.Threading.Thread.Sleep(30000); driver.Quit(); } } ## Biometric authentication (Finger Print, Touch Id) ### Android fingerprint authentication Emulate fingerprints on Android Emulator, with the [mobile:fingerprint](https://github.com/appium/appium-uiautomator2-driver?tab=readme-ov-file#mobile-fingerprint) command. Only works on API 23+ with [Appium version 2 or higher](https://testingbot.com/support/app-automate/appium/appium-versions). [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.AppiumDriver; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; import java.util.HashMap; public class FingerprintExample { public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platformName", "Android"); caps.setCapability("appium:deviceName", "Pixel 9"); caps.setCapability("browserName", "chrome"); caps.setCapability("browserVersion", "15"); caps.setCapability("tb:appiumVersion", "2.11.3"); AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps); HashMap args1 = new HashMap<>(); args1.put("fingerprintId", 1); driver.executeScript("mobile: fingerprint", args1); Thread.sleep(5000); driver.quit(); } } const { remote } = require('webdriverio'); (async () => { const caps = { platformName: 'Android', 'appium:deviceName': 'Pixel 9', browserName: 'chrome', browserVersion: '15', 'tb:appiumVersion': '2.11.3' }; const driver = await remote({ protocol: 'https', hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', user: 'key', key: 'secret', capabilities: caps }); await driver.executeScript('mobile: fingerprint', [{ fingerprintId: 1 }]); await driver.pause(5000); await driver.deleteSession(); })(); from appium import webdriver import time caps = { "platformName": "Android", "appium:deviceName": "Pixel 9", "browserName": "chrome", "browserVersion": "15", "tb:appiumVersion": "2.11.3" } driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps) # Simulate fingerprint auth with ID 1 driver.execute_script("mobile: fingerprint", { "fingerprintId": 1 }) time.sleep(5) driver.quit() require 'appium_lib' caps = { "platformName" => "Android", "appium:deviceName" => "Pixel 9", "browserName" => "chrome", "browserVersion" => "15", "tb:appiumVersion" => "2.11.3" } driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://key:secret@hub.testingbot.com/wd/hub" } }, true).start_driver driver.execute_script("mobile: fingerprint", { fingerprintId: 1 }) sleep 5 driver.quit using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; using OpenQA.Selenium.Appium; class FingerprintExample { static void Main(string[] args) { var options = new AppiumOptions(); options.PlatformName = "Android"; options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9"); options.AddAdditionalAppiumOption("browserName", "chrome"); options.AddAdditionalAppiumOption("browserVersion", "15"); options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3"); var driver = new RemoteWebDriver( new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options); driver.ExecuteScript("mobile: fingerprint", new Dictionary { { "fingerprintId", 1 } }); System.Threading.Thread.Sleep(5000); driver.Quit(); } } ### iOS TouchID/FaceID authentication You can simulate a biometric match/non-match event with TouchID and FaceID, with the [mobile: sendBiometricMatch](https://appium.github.io/appium-xcuitest-driver/latest/reference/execute-methods/#mobile-sendbiometricmatch) command. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.AppiumDriver; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; import java.util.HashMap; public class TouchIDExample { public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platformName", "iOS"); caps.setCapability("appium:deviceName", "iPhone 15"); caps.setCapability("appium:platformVersion", "18.0"); caps.setCapability("browserName", "safari"); caps.setCapability("tb:appiumVersion", "2.11.3"); AppiumDriver driver = new AppiumDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps); HashMap args1 = new HashMap<>(); args1.put("type", "touchId"); args1.put("match", true); driver.executeScript("mobile: sendBiometricMatch", args1); Thread.sleep(5000); HashMap args2 = new HashMap<>(); args2.put("type", "touchId"); args2.put("match", false); driver.executeScript("mobile: sendBiometricMatch", args2); Thread.sleep(5000); driver.quit(); } } const { remote } = require('webdriverio'); (async () => { const caps = { platformName: 'iOS', 'appium:deviceName': 'iPhone 15', 'appium:platformVersion': '18.0', browserName: 'safari', 'tb:appiumVersion': '2.11.3' }; const driver = await remote({ protocol: 'https', hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', user: 'key', key: 'secret', capabilities: caps }); // Successful Touch ID await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: true }]); await driver.pause(5000); // Failed Touch ID await driver.executeScript('mobile: sendBiometricMatch', [{ type: 'touchId', match: false }]); await driver.pause(5000); await driver.deleteSession(); })(); from appium import webdriver import time caps = { "platformName": "iOS", "appium:deviceName": "iPhone 15", "appium:platformVersion": "18.0", "browserName": "safari", "tb:appiumVersion": "2.11.3" } driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps) # Successful Touch ID driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": True }) time.sleep(5) # Failed Touch ID driver.execute_script("mobile: sendBiometricMatch", { "type": "touchId", "match": False }) time.sleep(5) driver.quit() require 'appium_lib' caps = { "platformName" => "iOS", "appium:deviceName" => "iPhone 15", "appium:platformVersion" => "18.0", "browserName" => "safari", "tb:appiumVersion" => "2.11.3" } driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://key:secret@hub.testingbot.com/wd/hub" } }, true).start_driver # Success driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: true }) sleep 5 # Failure driver.execute_script("mobile: sendBiometricMatch", { type: "touchId", match: false }) sleep 5 driver.quit using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; using OpenQA.Selenium.Appium; class TouchIDExample { static void Main(string[] args) { var options = new AppiumOptions(); options.PlatformName = "iOS"; options.AddAdditionalAppiumOption("appium:deviceName", "iPhone 15"); options.AddAdditionalAppiumOption("appium:platformVersion", "18.0"); options.AddAdditionalAppiumOption("browserName", "safari"); options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3"); var driver = new RemoteWebDriver( new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options); driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary { { "type", "touchId" }, { "match", true } }); System.Threading.Thread.Sleep(5000); driver.ExecuteScript("mobile: sendBiometricMatch", new Dictionary { { "type", "touchId" }, { "match", false } }); System.Threading.Thread.Sleep(5000); driver.Quit(); } } ## Receiving calls and text messages (SMS) You can simulate an incoming call or text message with Appium. Please see the examples below. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.AppiumDriver; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.connection.GsmCallActions; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; public class AndroidGsmExample { public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platformName", "Android"); caps.setCapability("appium:deviceName", "Pixel 9"); caps.setCapability("browserName", "chrome"); caps.setCapability("browserVersion", "15"); caps.setCapability("tb:appiumVersion", "2.11.3"); AndroidDriver driver = new AndroidDriver(new URL("https://key:secret@hub.testingbot.com/wd/hub"), caps); // Send SMS driver.sendSMS("5555555555", "Your message here!"); // Make and handle a phone call driver.makeGsmCall("5555555555", GsmCallActions.CALL); Thread.sleep(2000); driver.makeGsmCall("5555555555", GsmCallActions.ACCEPT); Thread.sleep(2000); driver.makeGsmCall("5555555555", GsmCallActions.CANCEL); driver.quit(); } } const { remote } = require('webdriverio'); (async () => { const caps = { platformName: 'Android', 'appium:deviceName': 'Pixel 9', browserName: 'chrome', browserVersion: '15', 'tb:appiumVersion': '2.11.3' }; const driver = await remote({ protocol: 'https', hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', user: 'key', key: 'secret', capabilities: caps }); // Send SMS await driver.sendSms('5555555555', 'Your message here!'); // Phone call await driver.makeGsmCall('5555555555', 'call'); await driver.pause(2000); await driver.makeGsmCall('5555555555', 'accept'); await driver.pause(2000); await driver.makeGsmCall('5555555555', 'cancel'); await driver.deleteSession(); })(); from appium import webdriver import time caps = { "platformName": "Android", "appium:deviceName": "Pixel 9", "browserName": "chrome", "browserVersion": "15", "tb:appiumVersion": "2.11.3" } driver = webdriver.Remote("https://key:secret@hub.testingbot.com/wd/hub", caps) # Send SMS driver.send_sms("5555555555", "Your message here!") # Phone call driver.make_gsm_call("5555555555", "call") time.sleep(2) driver.make_gsm_call("5555555555", "accept") time.sleep(2) driver.make_gsm_call("5555555555", "cancel") driver.quit() require 'appium_lib' caps = { "platformName" => "Android", "appium:deviceName" => "Pixel 9", "browserName" => "chrome", "browserVersion" => "15", "tb:appiumVersion" => "2.11.3" } driver = Appium::Driver.new({ caps: caps, appium_lib: { server_url: "https://key:secret@hub.testingbot.com/wd/hub" } }, true).start_driver # Send SMS driver.send_sms("5555555555", "Your message here!") # Phone call driver.make_gsm_call("5555555555", "call") sleep 2 driver.make_gsm_call("5555555555", "accept") sleep 2 driver.make_gsm_call("5555555555", "cancel") driver.quit using OpenQA.Selenium.Remote; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; using System; class AndroidGsmExample { static void Main(string[] args) { var options = new AppiumOptions(); options.PlatformName = "Android"; options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 9"); options.AddAdditionalAppiumOption("browserName", "chrome"); options.AddAdditionalAppiumOption("browserVersion", "15"); options.AddAdditionalAppiumOption("tb:appiumVersion", "2.11.3"); var driver = new AndroidDriver(new Uri("https://key:secret@hub.testingbot.com/wd/hub"), options); // Send SMS driver.SendSMS("5555555555", "Your message here!"); // Phone call driver.MakeGsmCall("5555555555", "call"); System.Threading.Thread.Sleep(2000); driver.MakeGsmCall("5555555555", "accept"); System.Threading.Thread.Sleep(2000); driver.MakeGsmCall("5555555555", "cancel"); driver.Quit(); } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest # XCUITest Intro TestingBot provides a grid of physical iOS devices in the cloud, ready to run your XCUITests. XCUITest (a framework within the larger XCTest Testing framework) is Apple's automation framework, which comes with Apple's XCode IDE, capable of running automated UI tests on iPhone and iPad devices. ## Setup XCUITest is packaged in a `zip` file. You will need two files to perform XCUITesting on our cloud: - An `.ipa` file of the actual mobile application that you want to test. - Another `.zip` file of the XCUITests. If you just want to give this a try, we have a [TestingBot XCUITest Demo App](https://github.com/testingbot/xcuitest-example-app) which you can use with the following steps. ## TestingBot CLI The easiest way to run XCUITests on TestingBot is using our CLI tool. It handles uploading your app, test ZIP, and running tests in a single command. ### Installation npm install -g @testingbot/cli ### Authentication Authenticate using this command: testingbot login This opens your browser for authentication. After logging in, your credentials are saved to `~/.testingbot` and you can start using the CLI. #### Other Authentication Methods - **Command-line options** : `--api-key` and `--api-secret` - **Environment variables** : `TB_KEY` and `TB_SECRET` - **Config file** : Create `~/.testingbot` with content `key:secret` ### Quick Start Run XCUITests with a single command: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device The CLI will: 1. Upload your app IPA to TestingBot 2. Upload your test ZIP 3. Start the test run 4. Show real-time progress and results ## Upload iOS App You can upload your `.ipa` file to TestingBot storage with our [REST-API](https://testingbot.com/support/api). [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, the app upload is handled automatically as part of the `testingbot xcuitest` command. Simply specify your app IPA file as the first argument: testingbot xcuitest /path/to/app/sample-debug.ipa /path/to/test/app-test.zip --device "iPhone 16" --real-device Alternatively, you can use the `--app` option: testingbot xcuitest --app /path/to/app/sample-debug.ipa --test-app /path/to/test/app-test.zip --device "iPhone 16" --real-device curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/app" \ -F "file=@/path/to/app/file/sample-debug.ipa" The API response will include an `id` response, which you can use in the other API calls. { "id": 4012 } ## Upload XCUITest Suite If you do not have a `.zip` file yet, please see our [Build Testsuite](https://testingbot.com/support/app-automate/xcuitest/build-testsuite) documentation. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) When using the CLI, the test ZIP upload is handled automatically. Specify your test ZIP as the second argument: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device Or use the `--test-app` option: testingbot xcuitest --app app.ipa --test-app app-test.zip --device "iPhone 16" --real-device To upload the XCUITest suite, in `.zip` file, please use our [REST-API](https://testingbot.com/support/api). curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/tests" \ -F "file=@/path/to/app/file/application-debug-test.zip" Replace the `:id` with the identifier you received during the app upload call. (In this example 4012) ## Run XCUI tests Once you've uploaded both your app and test suite, you can start a XCUITest on the TestingBot cloud. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Use the CLI to run tests with device selection options: # Basic usage with device selection testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device # With test name and build identifier testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 16" \ --real-device \ --name "Smoke Tests" \ --build "v2.1.0" #### Device Options | Option | Description | | --- | --- | | `--device ` | Device name (e.g., "iPhone 16", "iPad.\*") | | `--platform-version ` | iOS version (e.g., "17.0", "18.2") | | `--real-device` | Use a real device instead of simulator | | `--tablet-only` | Only allocate tablet devices (iPads) | | `--phone-only` | Only allocate phone devices (iPhones) | | `--orientation ` | Screen orientation: PORTRAIT or LANDSCAPE | #### Localization & Network # With localization settings testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 16" \ --real-device \ --locale "DE" \ --language "de" \ --timezone "Europe/Berlin" # With network throttling and geolocation testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 16" \ --real-device \ --throttle-network "3G" \ --geo-location "DE" Specify one or more capabilities, to indicate on which iOS devices you want to run your tests on. ![iOS selected](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg)iOS 18.2›iPhone 16 Loading environments... Please wait while we load the available browsers and platforms. Replace the `:id` with the identifier you received during the app upload call. (In this example 4012) We offer special parameters which you can use to allocate a device: Regex Input | Result || `"iPhone.*"` | This will allocate any available iPhone device (phone) | | `"*"` | This will allocate a random available device | | `"iPhone [8-11]"` | This will allocate either an iPhone 8 or 11 | | `"iPhone 6.*"` | This will allocate either an iPhone 6 or 6S | Some Examples: // find any iPhone, except 6 or 6s -d '{"capabilities":[{"deviceName":"^(iPhone.*)(?!6|6S)$", "platformName":"iOS", "realDevice": true}]}' // find any device which name starts with iPad -d '{"capabilities":[{"deviceName":"iPad.*", "platformName":"iOS", "realDevice": true}]}' ### Tablet Only You can specify the `tabletOnly` capability when you only want to allocate a tablet device. ### Phone Only You can specify the `phoneOnly` capability when you only want to allocate a phone device. -d '{"capabilities":[{"deviceName":"*", "tabletOnly": true, "platformName":"iOS", "realDevice": true}]}' -d '{"capabilities":[{"deviceName":"*", "phoneOnly": true, "platformName":"iOS", "realDevice": true}]}' ## View XCUITest Results The XCUITest results will be available in the [TestingBot dashboard](https://testingbot.com/members). Each test result contains a video, test logs and other meta data generated during the test run. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) By default, the CLI waits for test completion and displays real-time progress: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device The CLI will show: - Upload progress for app and test ZIP - Device allocation status - Live output from XCUITests - Final pass/fail status #### Async Mode Use `--async` to start tests without waiting for results: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device --async #### Download Reports Download a JUnit or HTML report after test completion: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device \ --report junit \ --report-output-dir ./reports You can also use an API call to get the results from the run(s): curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/xcuitest/:id" Replace the `:id` with the identifier you received during the app upload call. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/build-testsuite # Building XCUITest To test with XCUITest on TestingBot, you will need to build and export the XCUITests you have created. If you do not have a `zip` file of the XCUITest suite, you can follow the examples below. The `zip` file should contain a folder similar to this: xcuitest-sampleUITests-Runner.app ## Using XCode (13 and higher) 1. From the XCode schemes dropdown menu, select your app scheme and **Any iOS Device** as device 2. Click **Product -\> Clean** (`Cmd+Shift+K`) 3. Click **Product -\> Build For -\> Testing** (`Cmd+Shift+U`) 4. Go to **Product -\> Show Build Folder in Finder** 5. In Finder, navigate to **Products -\> Debug-iphoneos**. The directory should contain a file that ends with `-Runner.app`. Right click and choose the compress option to generate a `zip` file. ## Using XCode (Lower than 13.0) 1. From the XCode schemes dropdown menu, select your app scheme and **Generic iOS device** as device 2. Click **Product -\> Clean** (`Cmd+Shift+K`) 3. Click **Product -\> Build For -\> Testing** (`Cmd+Shift+U`) 4. Right click the `.app` file using the Project Navigator, and select **Show in Finder** 5. In Finder, the directory should contain a file called `-Runner.app`. Right click and choose the compress option to generate a `zip` file. ## Using Command Line To build the `.zip` file from the command line, please follow these steps: 1. Change to the project directory and build for testing: xcodebuild -scheme build-for-testing 2. Go to the **DerivedData** directory. To know the location of this directory, open Xcode and go to **Preferences -\> Locations**. 3. Now you can create the zip file. In the **DerivedData** directory, go to the directory containing the name of your app and some random characters. cd appname-random_characters cd Build/Products cd Debug-iphoneos zip --symlinks -r .zip -Runner.app Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/change-screen-orientation # Change Device Orientation You can change the iOS device's screen orientation before an XCUITest session starts by passing in a `orientation` option. ## Device Orientation Example See the example below on how to change the orientation. You can choose between `PORTRAIT` (default) and `LANDSCAPE`. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --orientation LANDSCAPE The default orientation is set to `PORTRAIT` for all XCUITests. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "orientation": "LANDSCAPE" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" The default orientation is set to `PORTRAIT` for all XCUITests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/instrumentation # XCUITest Instrumentation Logs Instrumentation logs are logs generated by XCUITest. These logs list all the steps that were performed during the test, with any errors or meta data available from the XCUITest runner. These logs are available in the [TestingBot dashboard](https://testingbot.com/members) as well as through the [REST API](https://testingbot.com/support/api). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/simulate-network-conditions # Simulate Network Conditions TestingBot allows you to test your mobile apps under various network conditions, including download speed, upload speed, packet loss and latency. ## Simulate network conditions using a predefined network profile TestingBot provides a set of predefined network profiles which you can choose from. Profile Name | Bandwidth down/up (kbps) | Packet Loss (%) | Latency (ms) || Edge | 250/150 | 0 | 300 | | 3G | 400/100 | 0 | 100 | | 4G | 18000/9000 | 0 | 100 | | airplane | 0 | 100 | 0 | [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --throttle-network "3G" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "throttle_network": "3G" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" ## Simulate network conditions using a custom network profile You can specify a custom set of parameters, including: - Download rate (kbps) - Upload rate (kbps) - Packet loss (%) - Latency (ms) [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) The CLI supports predefined network profiles. For custom network profiles, use the cURL API directly. # Predefined profiles: 4G, 3G, Edge, airplane testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --throttle-network "Edge" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "throttle_network": { "uploadSpeed": 10240, "downloadSpeed": 10240, "latency": 0, "loss": 0 } }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/set-localization-options # Set localization options TestingBot provides an option to run XCUITests on a localized version of your iOS mobile application. Configure the language, locale and timezone of the remote iOS device before running your XCUITest suite. ## Setting Language for iOS XCUI Tests Test a localized version of your mobile app with iOS XCUITest, by changing the language of the application under test. You will need to specify a `language` option with the ISO code of the language you want to use. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --language "fr" Use an [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to set the language of your app. Your app needs to be compiled with support for this language to notice a change. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "language": "fr" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" Use an [ISO 639-1 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) to set the language of your app. Your app needs to be compiled with support for this language to notice a change. ## Set a locale for XCUI Testing You can change the locale before running your XCUITest with the `locale` parameter. Please use the CA format (country name abbreviation). For example: `DE` for Germany. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --locale "DE" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "locale": "DE" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" ## Change timezone for XCUITests If you'd like to change the timezone before starting your XCUITests, you can use the `timeZone` option. Please use a timezone format from the [list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --timezone "America/New_York" curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "timeZone": "New_York" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/set-ip-geolocation # Use IP geolocation TestingBot's GeoIP feature allows you to test your app from various parts of the world, by using IP addresses in [over 20 different countries](https://testingbot.com/support/web-automate/selenium/test-options#geo). When you enable GeoIP, traffic originating from the iOS device which is running your XCUITest will come from an IP address in the country you specified. ## GeoIP example To get started with location testing, you can specify the geoLocation option when starting a XCUITest. Please see the example below where we specify that the app should connect through Germany. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 13" \ --real-device \ --geo-location "DE" The `DE` abbreviation is the ISO code of Germany. You can find other [GeoIP country codes](https://testingbot.com/support/web-automate/selenium/test-options#geo) to use. curl -u api_key:api_secret \ -X POST "https://api.testingbot.com/v1/app-automate/xcuitest/:id/run" \ -d '{ "options": { "geoLocation": "DE" }, "capabilities":[{"version":"15.5", "deviceName":"iPhone 13", "platformName":"iOS"}]}' \ -H "Content-Type: application/json" The `DE` abbreviation is the ISO code of Germany. You can find other [GeoIP country codes](https://testingbot.com/support/web-automate/selenium/test-options#geo) to use. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/app-automate/xcuitest/test-reports # XCUITest Reports TestingBot currently offers both test reports from inside the TestingBot member dashboard, or through REST-API where you can use a [JUnit formatted XML report](https://testingbot.com#junit). ## Dashboard Report When you run XCUITests with TestingBot, you will find the test results, together with a video of the test and various other logs, in the [TestingBot member dashboard](https://testingbot.com/members). ## API report You can query the TestingBot API to fetch the result of the XCUITest run(s). [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) By default, the CLI waits for test completion and displays results in real-time: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device The CLI will show: - Upload progress for app and test ZIP - Device allocation status - Live output from XCUITests - Final pass/fail status Use `--async` to start tests without waiting for results: testingbot xcuitest app.ipa app-test.zip --device "iPhone 16" --real-device --async curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/xcuitest/:id/:run_id" Replace the `:id` and `:run_id` with the identifiers you received during the app upload call and the run call. You will get back a response similar to this one: {"id":216,"created_at":"2024-04-04T15:49:47.000Z","status":"DONE","capabilities":{"deviceName":"iPhone .*","platformName":"iOS"},"success":false,"test":{"sessionId":"ffe-4b453ea45667-61a0a28dbf36-171224576223-3e","environment":{"name":"Safari","os":"iPhone 15 - 17.0","version":"17.0"}},"version":"1.0"} ## JUnit XML report You can query our API to fetch a JUnit XML report which you can use a post-build step in your CI/CD environment. **Report Structure** In the XML report, each session maps to a `testsuite` tag. Inside that tag, multiple `testcase` items are available, each mapping to a single XCUITest. If a test failed, a `failure` or `error` tag will be available. [CLI](https://testingbot.com#)[cURL](https://testingbot.com#) Download the JUnit XML report after test completion: testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 16" \ --real-device \ --report junit \ --report-output-dir ./reports You can also download an HTML report: testingbot xcuitest app.ipa app-test.zip \ --device "iPhone 16" \ --real-device \ --report html \ --report-output-dir ./reports curl -u api_key:api_secret \ "https://api.testingbot.com/v1/app-automate/xcuitest/:id/report" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate # Web Automation with TestingBot TestingBot provides a cloud-based platform for running automated tests on web applications, using various popular testing frameworks and tools. ![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg) ### [Selenium](https://testingbot.com/support/web-automate/selenium) Selenium is a popular test-framework, designed to automate website testing. - [Java](https://testingbot.com/support/web-automate/selenium/java) - [C#/.NET](https://testingbot.com/support/web-automate/selenium/csharp) - [NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs) - [Python](https://testingbot.com/support/web-automate/selenium/python) - [PHP](https://testingbot.com/support/web-automate/selenium/php) - [Ruby](https://testingbot.com/support/web-automate/selenium/ruby) ![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg) ### [Playwright](https://testingbot.com/support/web-automate/playwright) Playwright is a NodeJS library to automate Chromium, Firefox and WebKit. - [Java](https://testingbot.com/support/web-automate/playwright/java) - [C#/.NET](https://testingbot.com/support/web-automate/playwright/dotnet) - [Python](https://testingbot.com/support/web-automate/playwright/pytest) - [Jest](https://testingbot.com/support/web-automate/playwright/jest) ![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg) ### [Puppeteer](https://testingbot.com/support/web-automate/puppeteer) Puppeteer is a NodeJS library to automate Chrome and Firefox browsers. - [Jest](https://testingbot.com/support/web-automate/puppeteer/jest) - [WebdriverIO](https://testingbot.com/support/web-automate/puppeteer/webdriverio) - [CodeceptJS](https://testingbot.com/support/web-automate/puppeteer/codeceptjs) - [Scraping](https://testingbot.com/support/web-automate/puppeteer/scraping) ![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg) ### [Cypress](https://testingbot.com/support/web-automate/cypress) Cypress is a JavaScript-based end-to-end testing framework. - [Tutorial](https://testingbot.com/support/web-automate/cypress/tutorial) --- URL: https://testingbot.com/support/web-automate/headless # Headless Testing Documentation Headless testing **significantly minimizes the time it takes to run a test**. Because the browser runs in headless mode, it is not necessary to render the graphical user interface. This means the browser starts faster and uses less resources, resulting in quicker test execution. You can still take screenshots during headless mode. Video recording of the test however is not available in headless mode. ## Chrome Headless Testing To run headless tests on Chrome, simply set `headless: true` in `tb:options`. This tells TestingBot to launch the browser in headless mode and automatically disables video recording. We recommend using the `LINUX` platform for the fastest headless testing experience. [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[WebdriverIO](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)[PHP](https://testingbot.com#)[Robot Framework](https://testingbot.com#) import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class HeadlessChromeTest { public static void main(String[] args) throws Exception { ChromeOptions chromeOptions = new ChromeOptions(); chromeOptions.setPlatformName("LINUX"); chromeOptions.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); tbOptions.put("name", "Chrome Headless Test"); tbOptions.put("headless", true); chromeOptions.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver( new URL("https://hub.testingbot.com/wd/hub"), chromeOptions ); driver.get("https://www.google.com"); System.out.println("Title: " + driver.getTitle()); driver.quit(); } } from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.set_capability("platformName", "LINUX") chrome_options.set_capability("browserVersion", "latest") chrome_options.set_capability("tb:options", { "key": "api_key", "secret": "api_secret", "name": "Chrome Headless Test", "headless": True }) driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=chrome_options ) driver.get("https://www.google.com") print("Title:", driver.title) driver.quit() const { Builder } = require('selenium-webdriver'); async function runHeadlessTest() { const driver = await new Builder() .forBrowser('chrome') .withCapabilities({ 'browserName': 'chrome', 'browserVersion': 'latest', 'platformName': 'LINUX', 'tb:options': { 'key': 'api_key', 'secret': 'api_secret', 'name': 'Chrome Headless Test', 'headless': true } }) .usingServer('https://hub.testingbot.com/wd/hub') .build(); try { await driver.get('https://www.google.com'); const title = await driver.getTitle(); console.log('Title:', title); } finally { await driver.quit(); } } runHeadlessTest(); // wdio.conf.js exports.config = { user: 'api_key', key: 'api_secret', capabilities: [{ browserName: 'chrome', browserVersion: 'latest', platformName: 'LINUX', 'tb:options': { name: 'Chrome Headless Test', headless: true } }], services: [['testingbot']], // Your test configuration specs: ['./test/specs/**/*.js'], framework: 'mocha', reporters: ['spec'] }; // test/specs/example.js describe('Headless Chrome Test', () => { it('should load Google', async () => { await browser.url('https://www.google.com'); const title = await browser.getTitle(); console.log('Title:', title); }); }); require 'selenium-webdriver' options = Selenium::WebDriver::Chrome::Options.new options.platform_name = 'LINUX' options.browser_version = 'latest' caps = Selenium::WebDriver::Remote::Capabilities.new( 'tb:options': { key: 'api_key', secret: 'api_secret', name: 'Chrome Headless Test', headless: true } ) driver = Selenium::WebDriver.for( :remote, url: 'https://hub.testingbot.com/wd/hub', capabilities: [options, caps] ) driver.get('https://www.google.com') puts "Title: #{driver.title}" driver.quit using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; var chromeOptions = new ChromeOptions(); chromeOptions.PlatformName = "LINUX"; chromeOptions.BrowserVersion = "latest"; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "Chrome Headless Test", ["headless"] = true }; chromeOptions.AddAdditionalOption("tb:options", tbOptions); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600) ); driver.Navigate().GoToUrl("https://www.google.com"); Console.WriteLine("Title: " + driver.Title); driver.Quit(); setCapability('browserVersion', 'latest'); $capabilities->setCapability('platformName', 'LINUX'); $capabilities->setCapability('tb:options', [ 'key' => 'api_key', 'secret' => 'api_secret', 'name' => 'Chrome Headless Test', 'headless' => true ]); $driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities, 60000, 60000 ); $driver->get('https://www.google.com'); echo "Title: " . $driver->getTitle() . "\n"; $driver->quit(); ?> Save the example below in a `headless_chrome.robot` file: ***Settings*** Library SeleniumLibrary Library TestingBot Library Collections Test Setup Open Headless Chrome Browser Test Teardown Close Test Browser ***Variables*** ${TB_KEY} api_key ${TB_SECRET} api_secret ***Test Cases*** Chrome Headless Test Go To https://www.google.com Title Should Be Google ***Keywords*** Open Headless Chrome Browser ${chrome_options}= Evaluate selenium.webdriver.ChromeOptions() modules=selenium.webdriver # Set W3C capabilities Call Method ${chrome_options} set_capability platformName LINUX Call Method ${chrome_options} set_capability browserVersion latest # Set TestingBot options with headless enabled ${tb_options}= Create Dictionary name=Chrome Headless Test headless=${True} Call Method ${chrome_options} set_capability tb:options ${tb_options} Open Browser about:blank ... remote_url=https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub ... options=${chrome_options} Close Test Browser Report TestingBot Status ... ${SUITE_NAME} | ${TEST_NAME} ... ${TEST_STATUS} ... ${TB_KEY}:${TB_SECRET} Close All Browsers Save the code below in a `TestingBot.py` file: import requests from robot.libraries.BuiltIn import BuiltIn def report_testingbot_status(name, status, credentials): selenium = BuiltIn().get_library_instance('SeleniumLibrary') session_id = selenium.driver.session_id payload = {'test[name]': name, 'test[success]': int(status == 'PASS')} key, secret = credentials.split(':') url = 'https://api.testingbot.com/v1/tests/{0}'.format(session_id) response = requests.put(url, data=payload, auth=(key, secret)) assert response.status_code == 200, response.text To run the test: pip install robotframework-seleniumlibrary requests PYTHONPATH=$PYTHONPATH:. robot headless_chrome.robot ## Firefox Headless Testing To run headless tests on Firefox, simply set `headless: true` in `tb:options`. This tells TestingBot to launch the browser in headless mode and automatically disables video recording. [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[WebdriverIO](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)[PHP](https://testingbot.com#)[Robot Framework](https://testingbot.com#) import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class HeadlessFirefoxTest { public static void main(String[] args) throws Exception { FirefoxOptions firefoxOptions = new FirefoxOptions(); firefoxOptions.setPlatformName("LINUX"); firefoxOptions.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); tbOptions.put("name", "Firefox Headless Test"); tbOptions.put("headless", true); firefoxOptions.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver( new URL("https://hub.testingbot.com/wd/hub"), firefoxOptions ); driver.get("https://www.google.com"); System.out.println("Title: " + driver.getTitle()); driver.quit(); } } from selenium import webdriver from selenium.webdriver.firefox.options import Options firefox_options = Options() firefox_options.set_capability("platformName", "LINUX") firefox_options.set_capability("browserVersion", "latest") firefox_options.set_capability("tb:options", { "key": "api_key", "secret": "api_secret", "name": "Firefox Headless Test", "headless": True }) driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=firefox_options ) driver.get("https://www.google.com") print("Title:", driver.title) driver.quit() const { Builder } = require('selenium-webdriver'); async function runHeadlessTest() { const driver = await new Builder() .forBrowser('firefox') .withCapabilities({ 'browserName': 'firefox', 'browserVersion': 'latest', 'platformName': 'LINUX', 'tb:options': { 'key': 'api_key', 'secret': 'api_secret', 'name': 'Firefox Headless Test', 'headless': true } }) .usingServer('https://hub.testingbot.com/wd/hub') .build(); try { await driver.get('https://www.google.com'); const title = await driver.getTitle(); console.log('Title:', title); } finally { await driver.quit(); } } runHeadlessTest(); // wdio.conf.js exports.config = { user: 'api_key', key: 'api_secret', capabilities: [{ browserName: 'firefox', browserVersion: 'latest', platformName: 'LINUX', 'tb:options': { name: 'Firefox Headless Test', headless: true } }], services: [['testingbot']], // Your test configuration specs: ['./test/specs/**/*.js'], framework: 'mocha', reporters: ['spec'] }; // test/specs/example.js describe('Headless Firefox Test', () => { it('should load Google', async () => { await browser.url('https://www.google.com'); const title = await browser.getTitle(); console.log('Title:', title); }); }); require 'selenium-webdriver' options = Selenium::WebDriver::Firefox::Options.new options.platform_name = 'LINUX' options.browser_version = 'latest' caps = Selenium::WebDriver::Remote::Capabilities.new( 'tb:options': { key: 'api_key', secret: 'api_secret', name: 'Firefox Headless Test', headless: true } ) driver = Selenium::WebDriver.for( :remote, url: 'https://hub.testingbot.com/wd/hub', capabilities: [options, caps] ) driver.get('https://www.google.com') puts "Title: #{driver.title}" driver.quit using OpenQA.Selenium; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Remote; var firefoxOptions = new FirefoxOptions(); firefoxOptions.PlatformName = "LINUX"; firefoxOptions.BrowserVersion = "latest"; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "Firefox Headless Test", ["headless"] = true }; firefoxOptions.AddAdditionalOption("tb:options", tbOptions); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), firefoxOptions.ToCapabilities(), TimeSpan.FromSeconds(600) ); driver.Navigate().GoToUrl("https://www.google.com"); Console.WriteLine("Title: " + driver.Title); driver.Quit(); setCapability('browserVersion', 'latest'); $capabilities->setCapability('platformName', 'LINUX'); $capabilities->setCapability('tb:options', [ 'key' => 'api_key', 'secret' => 'api_secret', 'name' => 'Firefox Headless Test', 'headless' => true ]); $driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities, 60000, 60000 ); $driver->get('https://www.google.com'); echo "Title: " . $driver->getTitle() . "\n"; $driver->quit(); ?> Save the example below in a `headless_firefox.robot` file: ***Settings*** Library SeleniumLibrary Library TestingBot Library Collections Test Setup Open Headless Firefox Browser Test Teardown Close Test Browser ***Variables*** ${TB_KEY} api_key ${TB_SECRET} api_secret ***Test Cases*** Firefox Headless Test Go To https://www.google.com Title Should Be Google ***Keywords*** Open Headless Firefox Browser ${firefox_options}= Evaluate selenium.webdriver.FirefoxOptions() modules=selenium.webdriver # Set W3C capabilities Call Method ${firefox_options} set_capability platformName LINUX Call Method ${firefox_options} set_capability browserVersion latest # Set TestingBot options with headless enabled ${tb_options}= Create Dictionary name=Firefox Headless Test headless=${True} Call Method ${firefox_options} set_capability tb:options ${tb_options} Open Browser about:blank ... remote_url=https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub ... options=${firefox_options} Close Test Browser Report TestingBot Status ... ${SUITE_NAME} | ${TEST_NAME} ... ${TEST_STATUS} ... ${TB_KEY}:${TB_SECRET} Close All Browsers Save the code below in a `TestingBot.py` file: import requests from robot.libraries.BuiltIn import BuiltIn def report_testingbot_status(name, status, credentials): selenium = BuiltIn().get_library_instance('SeleniumLibrary') session_id = selenium.driver.session_id payload = {'test[name]': name, 'test[success]': int(status == 'PASS')} key, secret = credentials.split(':') url = 'https://api.testingbot.com/v1/tests/{0}'.format(session_id) response = requests.put(url, data=payload, auth=(key, secret)) assert response.status_code == 200, response.text To run the test: pip install robotframework-seleniumlibrary requests PYTHONPATH=$PYTHONPATH:. robot headless_firefox.robot ## Microsoft Edge Headless Testing To run headless tests on Microsoft Edge, simply set `headless: true` in `tb:options`. This tells TestingBot to launch the browser in headless mode and automatically disables video recording. We recommend using the `WIN11` or `WIN10` platform for Edge headless testing. [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[WebdriverIO](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#)[PHP](https://testingbot.com#)[Robot Framework](https://testingbot.com#) import org.openqa.selenium.WebDriver; import org.openqa.selenium.edge.EdgeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class HeadlessEdgeTest { public static void main(String[] args) throws Exception { EdgeOptions edgeOptions = new EdgeOptions(); edgeOptions.setPlatformName("WIN11"); edgeOptions.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); tbOptions.put("name", "Edge Headless Test"); tbOptions.put("headless", true); edgeOptions.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver( new URL("https://hub.testingbot.com/wd/hub"), edgeOptions ); driver.get("https://www.google.com"); System.out.println("Title: " + driver.getTitle()); driver.quit(); } } from selenium import webdriver from selenium.webdriver.edge.options import Options edge_options = Options() edge_options.set_capability("platformName", "WIN11") edge_options.set_capability("browserVersion", "latest") edge_options.set_capability("tb:options", { "key": "api_key", "secret": "api_secret", "name": "Edge Headless Test", "headless": True }) driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=edge_options ) driver.get("https://www.google.com") print("Title:", driver.title) driver.quit() const { Builder } = require('selenium-webdriver'); async function runHeadlessTest() { const driver = await new Builder() .forBrowser('MicrosoftEdge') .withCapabilities({ 'browserName': 'MicrosoftEdge', 'browserVersion': 'latest', 'platformName': 'WIN11', 'tb:options': { 'key': 'api_key', 'secret': 'api_secret', 'name': 'Edge Headless Test', 'headless': true } }) .usingServer('https://hub.testingbot.com/wd/hub') .build(); try { await driver.get('https://www.google.com'); const title = await driver.getTitle(); console.log('Title:', title); } finally { await driver.quit(); } } runHeadlessTest(); // wdio.conf.js exports.config = { user: 'api_key', key: 'api_secret', capabilities: [{ browserName: 'MicrosoftEdge', browserVersion: 'latest', platformName: 'WIN11', 'tb:options': { name: 'Edge Headless Test', headless: true } }], services: [['testingbot']], // Your test configuration specs: ['./test/specs/**/*.js'], framework: 'mocha', reporters: ['spec'] }; // test/specs/example.js describe('Headless Edge Test', () => { it('should load Google', async () => { await browser.url('https://www.google.com'); const title = await browser.getTitle(); console.log('Title:', title); }); }); require 'selenium-webdriver' options = Selenium::WebDriver::Edge::Options.new options.platform_name = 'WIN11' options.browser_version = 'latest' caps = Selenium::WebDriver::Remote::Capabilities.new( 'tb:options': { key: 'api_key', secret: 'api_secret', name: 'Edge Headless Test', headless: true } ) driver = Selenium::WebDriver.for( :remote, url: 'https://hub.testingbot.com/wd/hub', capabilities: [options, caps] ) driver.get('https://www.google.com') puts "Title: #{driver.title}" driver.quit using OpenQA.Selenium; using OpenQA.Selenium.Edge; using OpenQA.Selenium.Remote; var edgeOptions = new EdgeOptions(); edgeOptions.PlatformName = "WIN11"; edgeOptions.BrowserVersion = "latest"; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "Edge Headless Test", ["headless"] = true }; edgeOptions.AddAdditionalOption("tb:options", tbOptions); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), edgeOptions.ToCapabilities(), TimeSpan.FromSeconds(600) ); driver.Navigate().GoToUrl("https://www.google.com"); Console.WriteLine("Title: " + driver.Title); driver.Quit(); setCapability('browserVersion', 'latest'); $capabilities->setCapability('platformName', 'WIN11'); $capabilities->setCapability('tb:options', [ 'key' => 'api_key', 'secret' => 'api_secret', 'name' => 'Edge Headless Test', 'headless' => true ]); $driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities, 60000, 60000 ); $driver->get('https://www.google.com'); echo "Title: " . $driver->getTitle() . "\n"; $driver->quit(); ?> Save the example below in a `headless_edge.robot` file: ***Settings*** Library SeleniumLibrary Library TestingBot Library Collections Test Setup Open Headless Edge Browser Test Teardown Close Test Browser ***Variables*** ${TB_KEY} api_key ${TB_SECRET} api_secret ***Test Cases*** Edge Headless Test Go To https://www.google.com Title Should Be Google ***Keywords*** Open Headless Edge Browser ${edge_options}= Evaluate selenium.webdriver.EdgeOptions() modules=selenium.webdriver # Set W3C capabilities Call Method ${edge_options} set_capability platformName WIN11 Call Method ${edge_options} set_capability browserVersion latest # Set TestingBot options with headless enabled ${tb_options}= Create Dictionary name=Edge Headless Test headless=${True} Call Method ${edge_options} set_capability tb:options ${tb_options} Open Browser about:blank ... remote_url=https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub ... options=${edge_options} Close Test Browser Report TestingBot Status ... ${SUITE_NAME} | ${TEST_NAME} ... ${TEST_STATUS} ... ${TB_KEY}:${TB_SECRET} Close All Browsers Save the code below in a `TestingBot.py` file: import requests from robot.libraries.BuiltIn import BuiltIn def report_testingbot_status(name, status, credentials): selenium = BuiltIn().get_library_instance('SeleniumLibrary') session_id = selenium.driver.session_id payload = {'test[name]': name, 'test[success]': int(status == 'PASS')} key, secret = credentials.split(':') url = 'https://api.testingbot.com/v1/tests/{0}'.format(session_id) response = requests.put(url, data=payload, auth=(key, secret)) assert response.status_code == 200, response.text To run the test: pip install robotframework-seleniumlibrary requests PYTHONPATH=$PYTHONPATH:. robot headless_edge.robot ## Safari Headless Testing **Safari does not support headless mode.** Apple has not implemented headless functionality in Safari or the SafariDriver. If you need to run Safari tests, they will always run in headed (visible) mode. For headless testing requirements, consider using Chrome, Firefox or Edge as alternatives. At TestingBot we run all Safari 17 and higher versions on Apple Silicon for maximum performance. ## Mobile Headless Testing TestingBot uses Appium to run mobile tests. Appium supports running your iOS and Android tests in headless mode (no screen rendering). To enable headless mode for mobile testing, specify the `isHeadless` capability in your test configuration. ### iOS Headless Testing [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.ios.IOSDriver; import io.appium.java_client.ios.options.XCUITestOptions; import java.net.URL; import java.util.HashMap; import java.util.Map; public class HeadlessIOSTest { public static void main(String[] args) throws Exception { XCUITestOptions options = new XCUITestOptions(); options.setPlatformName("iOS"); options.setPlatformVersion("18.0"); options.setDeviceName("iPhone 16"); options.setBrowserName("safari"); options.setCapability("appium:isHeadless", true); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); tbOptions.put("name", "iOS Headless Test"); options.setCapability("tb:options", tbOptions); IOSDriver driver = new IOSDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); driver.get("https://www.google.com"); System.out.println("Title: " + driver.getTitle()); driver.quit(); } } from appium import webdriver from appium.options.ios import XCUITestOptions options = XCUITestOptions() options.platform_name = "iOS" options.platform_version = "18.0" options.device_name = "iPhone 16" options.browser_name = "safari" options.set_capability("appium:isHeadless", True) options.set_capability("tb:options", { "key": "api_key", "secret": "api_secret", "name": "iOS Headless Test" }) driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=options ) driver.get("https://www.google.com") print("Title:", driver.title) driver.quit() const { remote } = require('webdriverio'); async function runHeadlessIOSTest() { const driver = await remote({ hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', protocol: 'https', capabilities: { 'platformName': 'iOS', 'appium:platformVersion': '18.0', 'appium:deviceName': 'iPhone 16', 'browserName': 'safari', 'appium:isHeadless': true, 'tb:options': { 'key': 'api_key', 'secret': 'api_secret', 'name': 'iOS Headless Test' } } }); await driver.url('https://www.google.com'); const title = await driver.getTitle(); console.log('Title:', title); await driver.deleteSession(); } runHeadlessIOSTest(); require 'appium_lib' caps = { platformName: 'iOS', 'appium:platformVersion': '18.0', 'appium:deviceName': 'iPhone 16', browserName: 'safari', 'appium:isHeadless': true, 'tb:options': { key: 'api_key', secret: 'api_secret', name: 'iOS Headless Test' } } opts = { caps: caps, appium_lib: { server_url: 'https://hub.testingbot.com/wd/hub' } } driver = Appium::Driver.new(opts, true) driver.start_driver driver.get('https://www.google.com') puts "Title: #{driver.title}" driver.quit using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.iOS; var options = new AppiumOptions(); options.PlatformName = "iOS"; options.AddAdditionalAppiumOption("appium:platformVersion", "18.0"); options.AddAdditionalAppiumOption("appium:deviceName", "iPhone 16"); options.AddAdditionalAppiumOption("browserName", "safari"); options.AddAdditionalAppiumOption("appium:isHeadless", true); var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "iOS Headless Test" }; options.AddAdditionalAppiumOption("tb:options", tbOptions); var driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(600) ); driver.Navigate().GoToUrl("https://www.google.com"); Console.WriteLine("Title: " + driver.Title); driver.Quit(); ### Android Headless Testing [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Ruby](https://testingbot.com#)[C#](https://testingbot.com#) import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.android.options.UiAutomator2Options; import java.net.URL; import java.util.HashMap; import java.util.Map; public class HeadlessAndroidTest { public static void main(String[] args) throws Exception { UiAutomator2Options options = new UiAutomator2Options(); options.setPlatformName("Android"); options.setPlatformVersion("14.0"); options.setDeviceName("Pixel 8"); options.setBrowserName("chrome"); options.setCapability("appium:isHeadless", true); Map tbOptions = new HashMap<>(); tbOptions.put("key", "api_key"); tbOptions.put("secret", "api_secret"); tbOptions.put("name", "Android Headless Test"); options.setCapability("tb:options", tbOptions); AndroidDriver driver = new AndroidDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); driver.get("https://www.google.com"); System.out.println("Title: " + driver.getTitle()); driver.quit(); } } from appium import webdriver from appium.options.android import UiAutomator2Options options = UiAutomator2Options() options.platform_name = "Android" options.platform_version = "14.0" options.device_name = "Pixel 8" options.browser_name = "chrome" options.set_capability("appium:isHeadless", True) options.set_capability("tb:options", { "key": "api_key", "secret": "api_secret", "name": "Android Headless Test" }) driver = webdriver.Remote( command_executor="https://hub.testingbot.com/wd/hub", options=options ) driver.get("https://www.google.com") print("Title:", driver.title) driver.quit() const { remote } = require('webdriverio'); async function runHeadlessAndroidTest() { const driver = await remote({ hostname: 'hub.testingbot.com', port: 443, path: '/wd/hub', protocol: 'https', capabilities: { 'platformName': 'Android', 'appium:platformVersion': '14.0', 'appium:deviceName': 'Pixel 8', 'browserName': 'chrome', 'appium:isHeadless': true, 'tb:options': { 'key': 'api_key', 'secret': 'api_secret', 'name': 'Android Headless Test' } } }); await driver.url('https://www.google.com'); const title = await driver.getTitle(); console.log('Title:', title); await driver.deleteSession(); } runHeadlessAndroidTest(); require 'appium_lib' caps = { platformName: 'Android', 'appium:platformVersion': '14.0', 'appium:deviceName': 'Pixel 8', browserName: 'chrome', 'appium:isHeadless': true, 'tb:options': { key: 'api_key', secret: 'api_secret', name: 'Android Headless Test' } } opts = { caps: caps, appium_lib: { server_url: 'https://hub.testingbot.com/wd/hub' } } driver = Appium::Driver.new(opts, true) driver.start_driver driver.get('https://www.google.com') puts "Title: #{driver.title}" driver.quit using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Android; var options = new AppiumOptions(); options.PlatformName = "Android"; options.AddAdditionalAppiumOption("appium:platformVersion", "14.0"); options.AddAdditionalAppiumOption("appium:deviceName", "Pixel 8"); options.AddAdditionalAppiumOption("browserName", "chrome"); options.AddAdditionalAppiumOption("appium:isHeadless", true); var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "Android Headless Test" }; options.AddAdditionalAppiumOption("tb:options", tbOptions); var driver = new AndroidDriver( new Uri("https://hub.testingbot.com/wd/hub"), options, TimeSpan.FromSeconds(600) ); driver.Navigate().GoToUrl("https://www.google.com"); Console.WriteLine("Title: " + driver.Title); driver.Quit(); ## Benefits of Headless Testing - **Faster Test Execution:** Without rendering the UI, tests start and complete more quickly. - **Lower Resource Usage:** Headless browsers consume less memory and CPU. - **Ideal for CI/CD:** Perfect for automated pipelines where visual output is not needed. - **Screenshots Supported:** You can still capture screenshots during headless tests. ## Limitations - **No Video Recording:** Video recording is not available during headless tests. - **Debugging:** Debugging can be more challenging without seeing the browser UI. For debugging purposes, we recommend switching to headed mode temporarily to visually inspect the browser during test execution. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/browsers - [Desktop Browsers & Emulators](https://testingbot.com#) - [Physical Mobile Devices](https://testingbot.com/support/app-automate/devices) # List of available browsers Below is a list of **6031 combinations** available for testing. Click a combination to see how to run an automated or manual test. DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "%platform%"); caps.setCapability("version", "%version%"); caps.setCapability("browserName", "%browser%"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "%platform%"); caps.setCapability("version", "%version%"); caps.setCapability("browserName", "%browser%"); caps.setCapability("deviceName", "%deviceName%"); caps.setCapability("platformName", "%platformName%"); ### Test Configuration These are the DesiredCapabilities necessary to run an Automated Test: [Run Manual Test](https://testingbot.com/members/manual/new) ![Windows 11 Browser Testing](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg) ### Windows 11 (64-bit) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [dev](https://testingbot.com# "Edge")[beta](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80")[79](https://testingbot.com# "Edge 79") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [125](https://testingbot.com# "Opera 125")[124](https://testingbot.com# "Opera 124")[123](https://testingbot.com# "Opera 123")[122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![Windows 10 Browser Testing](https://testingbot.com/assets/environments/svg/windows10-f19b2b5055d9a272b1c8b35711154fc9cca1ae14442b48771e44680d28faffee.svg) ### Windows 10 (64-bit) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![iexplore](https://testingbot.com/assets/environments/svg/ie-075955285f8005808f3d26947aace877f96e5843a33bd4d6e997709d3a294451.svg "Iexplore") #### IE [11](https://testingbot.com# "IE11") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [dev](https://testingbot.com# "Edge")[beta](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80")[79](https://testingbot.com# "Edge 79") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [125](https://testingbot.com# "Opera 125")[124](https://testingbot.com# "Opera 124")[123](https://testingbot.com# "Opera 123")[122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![Windows 8 Browser Testing](https://testingbot.com/assets/environments/svg/windows10-f19b2b5055d9a272b1c8b35711154fc9cca1ae14442b48771e44680d28faffee.svg) ### Windows 8.1 (64-bit) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![iexplore](https://testingbot.com/assets/environments/svg/ie-075955285f8005808f3d26947aace877f96e5843a33bd4d6e997709d3a294451.svg "Iexplore") #### IE [11](https://testingbot.com# "IE11") ![Windows 8 Browser Testing](https://testingbot.com/assets/environments/svg/windows10-f19b2b5055d9a272b1c8b35711154fc9cca1ae14442b48771e44680d28faffee.svg) ### Windows 8 (64-bit) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![iexplore](https://testingbot.com/assets/environments/svg/ie-075955285f8005808f3d26947aace877f96e5843a33bd4d6e997709d3a294451.svg "Iexplore") #### IE [10](https://testingbot.com# "IE10") ![Windows 7 Browser Testing](https://testingbot.com/assets/environments/svg/windows-18aedb309faf40ff3447063f014404d18f2f97dee5deb28877d5f1e9787b2337.svg) ### Windows 7 (64-bit) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![iexplore](https://testingbot.com/assets/environments/svg/ie-075955285f8005808f3d26947aace877f96e5843a33bd4d6e997709d3a294451.svg "Iexplore") #### IE [11](https://testingbot.com# "IE11")[10](https://testingbot.com# "IE10")[9](https://testingbot.com# "IE9")[8](https://testingbot.com# "IE8") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![macOS Tahoe Browser Testing](https://testingbot.com/assets/environments/tahoe_logo-57c43a6991568db006f6302de4cda5171c2e1d56c4d3c0d81ce39ce7ae908146.png) ### macOS Tahoe (26.0) (ARM64) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [dev](https://testingbot.com# "Edge")[beta](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [26](https://testingbot.com# "Safari 26") ![macOS Sequoia Browser Testing](https://testingbot.com/assets/environments/sequoia_logo-44f79649144ee4151cccc4b7e5f154d15d9a7050e81617ce3a7b9be9a88de018.png) ### macOS Sequoia (15.0) (ARM64) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [beta](https://testingbot.com# "Edge")[dev](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [dev](https://testingbot.com# "Safari dev")[18](https://testingbot.com# "Safari 18") ![macOS Sonoma Browser Testing](https://testingbot.com/assets/environments/sonoma_logo-aeace52519331cc0c5c6e235d35f7ecb42e73abcbe5377d7518cfae7679cf403.png) ### macOS Sonoma (14.0) (ARM64) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [beta](https://testingbot.com# "Edge")[dev](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [beta](https://testingbot.com# "Safari beta")[dev](https://testingbot.com# "Safari dev")[17](https://testingbot.com# "Safari 17") ![macOS Ventura Browser Testing](https://testingbot.com/assets/environments/ventura_logo-2191cecf16bacb3874bc9b896158b59e375a8d0d79e47665a77188fba804a4ac.png) ### macOS Ventura (13.2) (ARM64) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [dev](https://testingbot.com# "Edge")[beta](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [beta](https://testingbot.com# "Safari beta")[dev](https://testingbot.com# "Safari dev")[16](https://testingbot.com# "Safari 16") ![macOS Monterey Browser Testing](https://testingbot.com/assets/environments/monterey_logo-ea303be67e778d42b57c65e88f1f7d2de9f4c7f9fc3845fc1f9e2000133a144c.png) ### macOS Monterey (12.6) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [dev](https://testingbot.com# "Edge")[143](https://testingbot.com# "Edge 143")[142](https://testingbot.com# "Edge 142")[141](https://testingbot.com# "Edge 141")[140](https://testingbot.com# "Edge 140")[139](https://testingbot.com# "Edge 139")[138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [125](https://testingbot.com# "Opera 125")[124](https://testingbot.com# "Opera 124")[123](https://testingbot.com# "Opera 123")[122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [beta](https://testingbot.com# "Safari beta")[dev](https://testingbot.com# "Safari dev")[15](https://testingbot.com# "Safari 15") ![macOS Big Sur Browser Testing](https://testingbot.com/assets/environments/bigsur_logo-a12e9501ec8d615b2196728977e14aabf6e10961fc5fcfb51670f949e50f8364.png) ### macOS Big Sur (11.6) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [138](https://testingbot.com# "Edge 138")[137](https://testingbot.com# "Edge 137")[136](https://testingbot.com# "Edge 136")[135](https://testingbot.com# "Edge 135")[134](https://testingbot.com# "Edge 134")[133](https://testingbot.com# "Edge 133")[132](https://testingbot.com# "Edge 132")[131](https://testingbot.com# "Edge 131")[130](https://testingbot.com# "Edge 130")[129](https://testingbot.com# "Edge 129")[128](https://testingbot.com# "Edge 128")[127](https://testingbot.com# "Edge 127")[126](https://testingbot.com# "Edge 126")[125](https://testingbot.com# "Edge 125")[124](https://testingbot.com# "Edge 124")[123](https://testingbot.com# "Edge 123")[122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [14](https://testingbot.com# "Safari 14") ![macOS Catalina Browser Testing](https://testingbot.com/assets/environments/catalina_logo-7e6a89b3b4f29856729312cc930ad86462d2ad73b3aef4c7a150b5214e85f688.png) ### macOS Catalina (10.15) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [dev](https://testingbot.com# "FF dev")[beta](https://testingbot.com# "FF beta")[146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [122](https://testingbot.com# "Edge 122")[121](https://testingbot.com# "Edge 121")[120](https://testingbot.com# "Edge 120")[119](https://testingbot.com# "Edge 119")[118](https://testingbot.com# "Edge 118")[117](https://testingbot.com# "Edge 117")[116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [125](https://testingbot.com# "Opera 125")[124](https://testingbot.com# "Opera 124")[123](https://testingbot.com# "Opera 123")[122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [13](https://testingbot.com# "Safari 13") ![macOS Mojave Browser Testing](https://testingbot.com/assets/environments/mojave_logo-55d4c0e36e23d7b1a7bc9b347619466a3311dda5b6e116385afdf504363c5d91.png) ### macOS Mojave (10.14) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![microsoftedge](https://testingbot.com/assets/environments/svg/edge-b639cac0c7a843271a0d3a6ccf894cc296064b63b2cd2920209bc5d030f3c70b.svg "Microsoftedge") #### Edge [116](https://testingbot.com# "Edge 116")[115](https://testingbot.com# "Edge 115")[114](https://testingbot.com# "Edge 114")[113](https://testingbot.com# "Edge 113")[112](https://testingbot.com# "Edge 112")[111](https://testingbot.com# "Edge 111")[110](https://testingbot.com# "Edge 110")[109](https://testingbot.com# "Edge 109")[108](https://testingbot.com# "Edge 108")[107](https://testingbot.com# "Edge 107")[106](https://testingbot.com# "Edge 106")[105](https://testingbot.com# "Edge 105")[104](https://testingbot.com# "Edge 104")[103](https://testingbot.com# "Edge 103")[102](https://testingbot.com# "Edge 102")[101](https://testingbot.com# "Edge 101")[100](https://testingbot.com# "Edge 100")[99](https://testingbot.com# "Edge 99")[98](https://testingbot.com# "Edge 98")[97](https://testingbot.com# "Edge 97")[96](https://testingbot.com# "Edge 96")[95](https://testingbot.com# "Edge 95")[94](https://testingbot.com# "Edge 94")[93](https://testingbot.com# "Edge 93")[92](https://testingbot.com# "Edge 92")[91](https://testingbot.com# "Edge 91")[90](https://testingbot.com# "Edge 90")[89](https://testingbot.com# "Edge 89")[88](https://testingbot.com# "Edge 88")[87](https://testingbot.com# "Edge 87")[86](https://testingbot.com# "Edge 86")[85](https://testingbot.com# "Edge 85")[84](https://testingbot.com# "Edge 84")[83](https://testingbot.com# "Edge 83")[81](https://testingbot.com# "Edge 81")[80](https://testingbot.com# "Edge 80")[79](https://testingbot.com# "Edge 79") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [12](https://testingbot.com# "Safari 12") ![macOS High-Sierra Browser Testing](https://testingbot.com/assets/environments/highsierra_logo-84730fb1f25dbf4fe5300d52b31494d8009d15b26ea893a5436040d58f19d2df.png) ### macOS High Sierra (10.13) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[36](https://testingbot.com# "Chrome 36") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91")[90](https://testingbot.com# "FF 90")[89](https://testingbot.com# "FF 89")[88](https://testingbot.com# "FF 88")[87](https://testingbot.com# "FF 87")[86](https://testingbot.com# "FF 86")[85](https://testingbot.com# "FF 85")[84](https://testingbot.com# "FF 84")[83](https://testingbot.com# "FF 83")[82](https://testingbot.com# "FF 82")[81](https://testingbot.com# "FF 81")[80](https://testingbot.com# "FF 80")[79](https://testingbot.com# "FF 79")[78](https://testingbot.com# "FF 78")[77](https://testingbot.com# "FF 77")[76](https://testingbot.com# "FF 76")[75](https://testingbot.com# "FF 75")[74](https://testingbot.com# "FF 74")[73](https://testingbot.com# "FF 73")[72](https://testingbot.com# "FF 72")[71](https://testingbot.com# "FF 71")[70](https://testingbot.com# "FF 70")[69](https://testingbot.com# "FF 69")[68](https://testingbot.com# "FF 68")[67](https://testingbot.com# "FF 67")[66](https://testingbot.com# "FF 66")[65](https://testingbot.com# "FF 65")[64](https://testingbot.com# "FF 64")[63](https://testingbot.com# "FF 63")[62](https://testingbot.com# "FF 62")[61](https://testingbot.com# "FF 61")[60](https://testingbot.com# "FF 60")[59](https://testingbot.com# "FF 59")[58](https://testingbot.com# "FF 58")[57](https://testingbot.com# "FF 57")[56](https://testingbot.com# "FF 56")[55](https://testingbot.com# "FF 55")[54](https://testingbot.com# "FF 54")[53](https://testingbot.com# "FF 53")[52](https://testingbot.com# "FF 52")[51](https://testingbot.com# "FF 51")[50](https://testingbot.com# "FF 50")[49](https://testingbot.com# "FF 49")[48](https://testingbot.com# "FF 48")[47](https://testingbot.com# "FF 47")[46](https://testingbot.com# "FF 46")[45](https://testingbot.com# "FF 45")[44](https://testingbot.com# "FF 44")[43](https://testingbot.com# "FF 43")[42](https://testingbot.com# "FF 42")[41](https://testingbot.com# "FF 41")[40](https://testingbot.com# "FF 40")[39](https://testingbot.com# "FF 39")[38](https://testingbot.com# "FF 38")[37](https://testingbot.com# "FF 37")[36](https://testingbot.com# "FF 36")[35](https://testingbot.com# "FF 35")[34](https://testingbot.com# "FF 34")[33](https://testingbot.com# "FF 33")[32](https://testingbot.com# "FF 32")[31](https://testingbot.com# "FF 31")[30](https://testingbot.com# "FF 30")[29](https://testingbot.com# "FF 29")[28](https://testingbot.com# "FF 28")[27](https://testingbot.com# "FF 27")[26](https://testingbot.com# "FF 26")[25](https://testingbot.com# "FF 25")[24](https://testingbot.com# "FF 24")[23](https://testingbot.com# "FF 23")[22](https://testingbot.com# "FF 22")[21](https://testingbot.com# "FF 21")[20](https://testingbot.com# "FF 20")[19](https://testingbot.com# "FF 19")[18](https://testingbot.com# "FF 18")[17](https://testingbot.com# "FF 17")[16](https://testingbot.com# "FF 16")[15](https://testingbot.com# "FF 15")[14](https://testingbot.com# "FF 14")[13](https://testingbot.com# "FF 13")[12](https://testingbot.com# "FF 12")[11](https://testingbot.com# "FF 11")[10](https://testingbot.com# "FF 10")[9](https://testingbot.com# "FF 9")[8](https://testingbot.com# "FF 8")[7](https://testingbot.com# "FF 7")[6](https://testingbot.com# "FF 6")[5](https://testingbot.com# "FF 5")[4](https://testingbot.com# "FF 4") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79")[78](https://testingbot.com# "Opera 78")[77](https://testingbot.com# "Opera 77")[76](https://testingbot.com# "Opera 76")[75](https://testingbot.com# "Opera 75")[74](https://testingbot.com# "Opera 74")[73](https://testingbot.com# "Opera 73")[72](https://testingbot.com# "Opera 72")[71](https://testingbot.com# "Opera 71")[70](https://testingbot.com# "Opera 70")[69](https://testingbot.com# "Opera 69")[68](https://testingbot.com# "Opera 68")[67](https://testingbot.com# "Opera 67")[66](https://testingbot.com# "Opera 66")[65](https://testingbot.com# "Opera 65")[64](https://testingbot.com# "Opera 64")[63](https://testingbot.com# "Opera 63")[62](https://testingbot.com# "Opera 62")[60](https://testingbot.com# "Opera 60")[59](https://testingbot.com# "Opera 59")[58](https://testingbot.com# "Opera 58")[57](https://testingbot.com# "Opera 57")[56](https://testingbot.com# "Opera 56")[55](https://testingbot.com# "Opera 55")[54](https://testingbot.com# "Opera 54")[53](https://testingbot.com# "Opera 53")[52](https://testingbot.com# "Opera 52")[51](https://testingbot.com# "Opera 51")[50](https://testingbot.com# "Opera 50") ![safari](https://testingbot.com/assets/environments/svg/safari-e4837bb5f9a9729fef843af4180372e975c62587808b8ab479f615f3e240e858.svg "Safari") #### Safari [11](https://testingbot.com# "Safari 11") ![Linux Browser Testing](https://testingbot.com/assets/environments/linux_logo-3bf359ff8b03f3abf649e853e44e89515c60c7ca40a5c09e6281e3d61e2d0e16.png) ### Linux (Ubuntu 22.04) ![googlechrome](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg "Googlechrome") #### Chrome [beta](https://testingbot.com# "Chrome")[dev](https://testingbot.com# "Chrome")[143](https://testingbot.com# "Chrome 143")[142](https://testingbot.com# "Chrome 142")[141](https://testingbot.com# "Chrome 141")[140](https://testingbot.com# "Chrome 140")[139](https://testingbot.com# "Chrome 139")[138](https://testingbot.com# "Chrome 138")[137](https://testingbot.com# "Chrome 137")[136](https://testingbot.com# "Chrome 136")[135](https://testingbot.com# "Chrome 135")[134](https://testingbot.com# "Chrome 134")[133](https://testingbot.com# "Chrome 133")[132](https://testingbot.com# "Chrome 132")[131](https://testingbot.com# "Chrome 131")[130](https://testingbot.com# "Chrome 130")[129](https://testingbot.com# "Chrome 129")[128](https://testingbot.com# "Chrome 128")[127](https://testingbot.com# "Chrome 127")[126](https://testingbot.com# "Chrome 126")[125](https://testingbot.com# "Chrome 125")[124](https://testingbot.com# "Chrome 124")[123](https://testingbot.com# "Chrome 123")[122](https://testingbot.com# "Chrome 122")[121](https://testingbot.com# "Chrome 121")[120](https://testingbot.com# "Chrome 120")[119](https://testingbot.com# "Chrome 119")[118](https://testingbot.com# "Chrome 118")[117](https://testingbot.com# "Chrome 117")[116](https://testingbot.com# "Chrome 116")[115](https://testingbot.com# "Chrome 115")[114](https://testingbot.com# "Chrome 114")[113](https://testingbot.com# "Chrome 113")[112](https://testingbot.com# "Chrome 112")[111](https://testingbot.com# "Chrome 111")[110](https://testingbot.com# "Chrome 110")[109](https://testingbot.com# "Chrome 109")[108](https://testingbot.com# "Chrome 108")[107](https://testingbot.com# "Chrome 107")[106](https://testingbot.com# "Chrome 106")[105](https://testingbot.com# "Chrome 105")[104](https://testingbot.com# "Chrome 104")[103](https://testingbot.com# "Chrome 103")[102](https://testingbot.com# "Chrome 102")[101](https://testingbot.com# "Chrome 101")[100](https://testingbot.com# "Chrome 100")[99](https://testingbot.com# "Chrome 99")[98](https://testingbot.com# "Chrome 98")[97](https://testingbot.com# "Chrome 97")[96](https://testingbot.com# "Chrome 96")[95](https://testingbot.com# "Chrome 95")[94](https://testingbot.com# "Chrome 94")[93](https://testingbot.com# "Chrome 93")[92](https://testingbot.com# "Chrome 92")[91](https://testingbot.com# "Chrome 91")[90](https://testingbot.com# "Chrome 90")[89](https://testingbot.com# "Chrome 89")[88](https://testingbot.com# "Chrome 88")[87](https://testingbot.com# "Chrome 87")[86](https://testingbot.com# "Chrome 86")[85](https://testingbot.com# "Chrome 85")[84](https://testingbot.com# "Chrome 84")[83](https://testingbot.com# "Chrome 83")[81](https://testingbot.com# "Chrome 81")[80](https://testingbot.com# "Chrome 80")[79](https://testingbot.com# "Chrome 79")[78](https://testingbot.com# "Chrome 78")[77](https://testingbot.com# "Chrome 77")[76](https://testingbot.com# "Chrome 76")[75](https://testingbot.com# "Chrome 75")[74](https://testingbot.com# "Chrome 74")[73](https://testingbot.com# "Chrome 73")[72](https://testingbot.com# "Chrome 72")[71](https://testingbot.com# "Chrome 71")[70](https://testingbot.com# "Chrome 70")[69](https://testingbot.com# "Chrome 69")[68](https://testingbot.com# "Chrome 68")[67](https://testingbot.com# "Chrome 67")[66](https://testingbot.com# "Chrome 66")[65](https://testingbot.com# "Chrome 65")[64](https://testingbot.com# "Chrome 64")[63](https://testingbot.com# "Chrome 63")[62](https://testingbot.com# "Chrome 62")[61](https://testingbot.com# "Chrome 61")[60](https://testingbot.com# "Chrome 60")[59](https://testingbot.com# "Chrome 59")[58](https://testingbot.com# "Chrome 58")[57](https://testingbot.com# "Chrome 57")[56](https://testingbot.com# "Chrome 56")[55](https://testingbot.com# "Chrome 55")[54](https://testingbot.com# "Chrome 54")[53](https://testingbot.com# "Chrome 53")[52](https://testingbot.com# "Chrome 52")[51](https://testingbot.com# "Chrome 51")[50](https://testingbot.com# "Chrome 50")[49](https://testingbot.com# "Chrome 49")[48](https://testingbot.com# "Chrome 48")[47](https://testingbot.com# "Chrome 47")[46](https://testingbot.com# "Chrome 46")[45](https://testingbot.com# "Chrome 45")[44](https://testingbot.com# "Chrome 44")[43](https://testingbot.com# "Chrome 43")[42](https://testingbot.com# "Chrome 42")[41](https://testingbot.com# "Chrome 41")[40](https://testingbot.com# "Chrome 40")[39](https://testingbot.com# "Chrome 39")[38](https://testingbot.com# "Chrome 38")[37](https://testingbot.com# "Chrome 37") ![firefox](https://testingbot.com/assets/environments/svg/firefox-90dce8de549728e54bd3209cfacb9f1a868c2c8e70d243eb5b930d69cbb2fb1e.svg "Firefox") #### Firefox [146](https://testingbot.com# "FF 146")[145](https://testingbot.com# "FF 145")[144](https://testingbot.com# "FF 144")[143](https://testingbot.com# "FF 143")[142](https://testingbot.com# "FF 142")[141](https://testingbot.com# "FF 141")[140](https://testingbot.com# "FF 140")[139](https://testingbot.com# "FF 139")[138](https://testingbot.com# "FF 138")[137](https://testingbot.com# "FF 137")[136](https://testingbot.com# "FF 136")[135](https://testingbot.com# "FF 135")[134](https://testingbot.com# "FF 134")[133](https://testingbot.com# "FF 133")[132](https://testingbot.com# "FF 132")[131](https://testingbot.com# "FF 131")[130](https://testingbot.com# "FF 130")[129](https://testingbot.com# "FF 129")[128](https://testingbot.com# "FF 128")[127](https://testingbot.com# "FF 127")[126](https://testingbot.com# "FF 126")[125](https://testingbot.com# "FF 125")[124](https://testingbot.com# "FF 124")[123](https://testingbot.com# "FF 123")[122](https://testingbot.com# "FF 122")[121](https://testingbot.com# "FF 121")[120](https://testingbot.com# "FF 120")[119](https://testingbot.com# "FF 119")[118](https://testingbot.com# "FF 118")[117](https://testingbot.com# "FF 117")[116](https://testingbot.com# "FF 116")[115](https://testingbot.com# "FF 115")[114](https://testingbot.com# "FF 114")[113](https://testingbot.com# "FF 113")[112](https://testingbot.com# "FF 112")[111](https://testingbot.com# "FF 111")[110](https://testingbot.com# "FF 110")[109](https://testingbot.com# "FF 109")[108](https://testingbot.com# "FF 108")[107](https://testingbot.com# "FF 107")[106](https://testingbot.com# "FF 106")[105](https://testingbot.com# "FF 105")[104](https://testingbot.com# "FF 104")[103](https://testingbot.com# "FF 103")[102](https://testingbot.com# "FF 102")[101](https://testingbot.com# "FF 101")[100](https://testingbot.com# "FF 100")[99](https://testingbot.com# "FF 99")[98](https://testingbot.com# "FF 98")[97](https://testingbot.com# "FF 97")[96](https://testingbot.com# "FF 96")[95](https://testingbot.com# "FF 95")[94](https://testingbot.com# "FF 94")[93](https://testingbot.com# "FF 93")[92](https://testingbot.com# "FF 92")[91](https://testingbot.com# "FF 91") ![opera](https://testingbot.com/assets/environments/svg/opera-fe6e1d716472033125a969dfe6489ab45f0eded91e9260292d6c4ce9b682a330.svg "Opera") #### Opera [125](https://testingbot.com# "Opera 125")[124](https://testingbot.com# "Opera 124")[123](https://testingbot.com# "Opera 123")[122](https://testingbot.com# "Opera 122")[121](https://testingbot.com# "Opera 121")[120](https://testingbot.com# "Opera 120")[119](https://testingbot.com# "Opera 119")[118](https://testingbot.com# "Opera 118")[117](https://testingbot.com# "Opera 117")[116](https://testingbot.com# "Opera 116")[115](https://testingbot.com# "Opera 115")[114](https://testingbot.com# "Opera 114")[113](https://testingbot.com# "Opera 113")[112](https://testingbot.com# "Opera 112")[111](https://testingbot.com# "Opera 111")[110](https://testingbot.com# "Opera 110")[109](https://testingbot.com# "Opera 109")[108](https://testingbot.com# "Opera 108")[107](https://testingbot.com# "Opera 107")[106](https://testingbot.com# "Opera 106")[105](https://testingbot.com# "Opera 105")[104](https://testingbot.com# "Opera 104")[103](https://testingbot.com# "Opera 103")[102](https://testingbot.com# "Opera 102")[101](https://testingbot.com# "Opera 101")[100](https://testingbot.com# "Opera 100")[99](https://testingbot.com# "Opera 99")[98](https://testingbot.com# "Opera 98")[97](https://testingbot.com# "Opera 97")[96](https://testingbot.com# "Opera 96")[95](https://testingbot.com# "Opera 95")[94](https://testingbot.com# "Opera 94")[93](https://testingbot.com# "Opera 93")[92](https://testingbot.com# "Opera 92")[91](https://testingbot.com# "Opera 91")[90](https://testingbot.com# "Opera 90")[89](https://testingbot.com# "Opera 89")[88](https://testingbot.com# "Opera 88")[87](https://testingbot.com# "Opera 87")[86](https://testingbot.com# "Opera 86")[85](https://testingbot.com# "Opera 85")[84](https://testingbot.com# "Opera 84")[83](https://testingbot.com# "Opera 83")[82](https://testingbot.com# "Opera 82")[81](https://testingbot.com# "Opera 81")[80](https://testingbot.com# "Opera 80")[79](https://testingbot.com# "Opera 79") ![iOS Browser Testing](https://testingbot.com/assets/environments/svg/ios-383468addf160fa18d0e431f529420739d7f7d1206175f682fead627d2e99a52.svg) ### iOS Simulators #### Phones ##### 26.0 [iPhone 17 Pro Max (26.0)](https://testingbot.com# "iPhone 17 Pro Max - 26.0")[iPhone 17 Pro (26.0)](https://testingbot.com# "iPhone 17 Pro - 26.0")[iPhone 17 (26.0)](https://testingbot.com# "iPhone 17 - 26.0")[iPhone 16e (26.0)](https://testingbot.com# "iPhone 16e - 26.0")[iPhone Air (26.0)](https://testingbot.com# "iPhone Air - 26.0") ##### 18.6 [iPhone 16 Pro Max (18.6)](https://testingbot.com# "iPhone 16 Pro Max - 18.6")[iPhone 16 Pro (18.6)](https://testingbot.com# "iPhone 16 Pro - 18.6")[iPhone 16 Plus (18.6)](https://testingbot.com# "iPhone 16 Plus - 18.6")[iPhone 16 (18.6)](https://testingbot.com# "iPhone 16 - 18.6")[iPhone 16e (18.6)](https://testingbot.com# "iPhone 16e - 18.6") ##### 18.3 [iPhone 16 (18.3)](https://testingbot.com# "iPhone 16 - 18.3")[iPhone 16e (18.3)](https://testingbot.com# "iPhone 16e - 18.3")[iPhone 16 Plus (18.3)](https://testingbot.com# "iPhone 16 Plus - 18.3")[iPhone 16 Pro (18.3)](https://testingbot.com# "iPhone 16 Pro - 18.3")[iPhone 16 Pro Max (18.3)](https://testingbot.com# "iPhone 16 Pro Max - 18.3") ##### 18.0 [iPhone 16 (18.0)](https://testingbot.com# "iPhone 16 - 18.0")[iPhone 16 Plus (18.0)](https://testingbot.com# "iPhone 16 Plus - 18.0")[iPhone 16 Pro (18.0)](https://testingbot.com# "iPhone 16 Pro - 18.0")[iPhone 16 Pro Max (18.0)](https://testingbot.com# "iPhone 16 Pro Max - 18.0")[iPhone SE (3rd generation) (18.0)](https://testingbot.com# "iPhone SE (3rd generation) - 18.0") ##### 17.5 [iPhone 15 (17.5)](https://testingbot.com# "iPhone 15 - 17.5")[iPhone 15 Plus (17.5)](https://testingbot.com# "iPhone 15 Plus - 17.5")[iPhone 15 Pro (17.5)](https://testingbot.com# "iPhone 15 Pro - 17.5")[iPhone 15 Pro Max (17.5)](https://testingbot.com# "iPhone 15 Pro Max - 17.5")[iPhone SE (3rd generation) (17.5)](https://testingbot.com# "iPhone SE (3rd generation) - 17.5") ##### 17.4 [iPhone 15 (17.4)](https://testingbot.com# "iPhone 15 - 17.4")[iPhone 15 Plus (17.4)](https://testingbot.com# "iPhone 15 Plus - 17.4")[iPhone 15 Pro (17.4)](https://testingbot.com# "iPhone 15 Pro - 17.4")[iPhone 15 Pro Max (17.4)](https://testingbot.com# "iPhone 15 Pro Max - 17.4")[iPhone SE (3rd generation) (17.4)](https://testingbot.com# "iPhone SE (3rd generation) - 17.4") ##### 17.2 [iPhone 15 (17.2)](https://testingbot.com# "iPhone 15 - 17.2")[iPhone 15 Plus (17.2)](https://testingbot.com# "iPhone 15 Plus - 17.2")[iPhone 15 Pro (17.2)](https://testingbot.com# "iPhone 15 Pro - 17.2")[iPhone 15 Pro Max (17.2)](https://testingbot.com# "iPhone 15 Pro Max - 17.2")[iPhone SE (3rd generation) (17.2)](https://testingbot.com# "iPhone SE (3rd generation) - 17.2") ##### 17.0 [iPhone 15 (17.0)](https://testingbot.com# "iPhone 15 - 17.0")[iPhone 15 Plus (17.0)](https://testingbot.com# "iPhone 15 Plus - 17.0")[iPhone 15 Pro (17.0)](https://testingbot.com# "iPhone 15 Pro - 17.0")[iPhone 15 Pro Max (17.0)](https://testingbot.com# "iPhone 15 Pro Max - 17.0")[iPhone SE (3rd generation) (17.0)](https://testingbot.com# "iPhone SE (3rd generation) - 17.0") ##### 16.2 [iPhone 14 (16.2)](https://testingbot.com# "iPhone 14 - 16.2")[iPhone 14 Plus (16.2)](https://testingbot.com# "iPhone 14 Plus - 16.2")[iPhone 14 Pro (16.2)](https://testingbot.com# "iPhone 14 Pro - 16.2")[iPhone 14 Pro Max (16.2)](https://testingbot.com# "iPhone 14 Pro Max - 16.2") ##### 16.0 [iPhone 14 (16.0)](https://testingbot.com# "iPhone 14 - 16.0")[iPhone 14 Pro (16.0)](https://testingbot.com# "iPhone 14 Pro - 16.0")[iPhone 14 Pro Max (16.0)](https://testingbot.com# "iPhone 14 Pro Max - 16.0")[iPhone 14 Plus (16.0)](https://testingbot.com# "iPhone 14 Plus - 16.0")[iPhone SE (3rd generation) (16.0)](https://testingbot.com# "iPhone SE (3rd generation) - 16.0") #### Tablets ##### 26.0 [iPad (A16) (26.0)](https://testingbot.com# "iPad (A16) - 26.0")[iPad Pro (13-inch) (M4) (26.0)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 26.0")[iPad Air 13-inch (M3) (26.0)](https://testingbot.com# "iPad Air 13-inch (M3) - 26.0")[iPad Pro (11-inch) (M4) (26.0)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 26.0")[iPad Air 11-inch (M3) (26.0)](https://testingbot.com# "iPad Air 11-inch (M3) - 26.0") ##### 18.6 [iPad Mini (A17 Pro) (18.6)](https://testingbot.com# "iPad Mini (A17 Pro) - 18.6")[iPad (A16) (18.6)](https://testingbot.com# "iPad (A16) - 18.6")[iPad Air 13-inch (M3) (18.6)](https://testingbot.com# "iPad Air 13-inch (M3) - 18.6")[iPad Pro (13-inch) (M4) (18.6)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 18.6")[iPad Pro (11-inch) (M4) (18.6)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 18.6")[iPad Air 11-inch (M3) (18.6)](https://testingbot.com# "iPad Air 11-inch (M3) - 18.6") ##### 18.3 [iPad (A16) (18.3)](https://testingbot.com# "iPad (A16) - 18.3")[iPad Air 13-inch (M3) (18.3)](https://testingbot.com# "iPad Air 13-inch (M3) - 18.3")[iPad Pro (13-inch) (M4) (18.3)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 18.3")[iPad Pro (11-inch) (M4) (18.3)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 18.3")[iPad Air 11-inch (M3) (18.3)](https://testingbot.com# "iPad Air 11-inch (M3) - 18.3") ##### 18.0 [iPad Pro (13-inch) (M4) (18.0)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 18.0")[iPad Air 13-inch (M2) (18.0)](https://testingbot.com# "iPad Air 13-inch (M2) - 18.0")[iPad Pro (11-inch) (M4) (18.0)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 18.0")[iPad Air 11-inch (M2) (18.0)](https://testingbot.com# "iPad Air 11-inch (M2) - 18.0") ##### 17.5 [iPad Air 13-inch (M2) (17.5)](https://testingbot.com# "iPad Air 13-inch (M2) - 17.5")[iPad Pro (13-inch) (M4) (17.5)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 17.5")[iPad Pro (11-inch) (M4) (17.5)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 17.5")[iPad Air 11-inch (M2) (17.5)](https://testingbot.com# "iPad Air 11-inch (M2) - 17.5") ##### 17.4 [iPad Pro (13-inch) (M4) (17.4)](https://testingbot.com# "iPad Pro (13-inch) (M4) - 17.4")[iPad Air 13-inch (M2) (17.4)](https://testingbot.com# "iPad Air 13-inch (M2) - 17.4")[iPad Pro (11-inch) (M4) (17.4)](https://testingbot.com# "iPad Pro (11-inch) (M4) - 17.4")[iPad Air 11-inch (M2) (17.4)](https://testingbot.com# "iPad Air 11-inch (M2) - 17.4") ##### 17.2 [iPad Pro (12.9-inch) (6th generation) (17.2)](https://testingbot.com# "iPad Pro (12.9-inch) (6th generation) - 17.2")[iPad Pro (11-inch) (4th generation) (17.2)](https://testingbot.com# "iPad Pro (11-inch) (4th generation) - 17.2")[iPad (10th generation) (17.2)](https://testingbot.com# "iPad (10th generation) - 17.2")[iPad mini (6th generation) (17.2)](https://testingbot.com# "iPad mini (6th generation) - 17.2")[iPad Air (5th generation) (17.2)](https://testingbot.com# "iPad Air (5th generation) - 17.2") ##### 17.0 [iPad Pro (12.9-inch) (6th generation) (17.0)](https://testingbot.com# "iPad Pro (12.9-inch) (6th generation) - 17.0")[iPad Pro (11-inch) (4th generation) (17.0)](https://testingbot.com# "iPad Pro (11-inch) (4th generation) - 17.0")[iPad (10th generation) (17.0)](https://testingbot.com# "iPad (10th generation) - 17.0")[iPad mini (6th generation) (17.0)](https://testingbot.com# "iPad mini (6th generation) - 17.0")[iPad Air (5th generation) (17.0)](https://testingbot.com# "iPad Air (5th generation) - 17.0") ##### 16.2 [iPad Pro (12.9-inch) (6th generation) (16.2)](https://testingbot.com# "iPad Pro (12.9-inch) (6th generation) - 16.2")[iPad Pro (11-inch) (4th generation) (16.2)](https://testingbot.com# "iPad Pro (11-inch) (4th generation) - 16.2")[iPad (10th generation) (16.2)](https://testingbot.com# "iPad (10th generation) - 16.2")[iPad Air (5th generation) (16.2)](https://testingbot.com# "iPad Air (5th generation) - 16.2") ##### 16.0 [iPad Pro (12.9-inch) (5th generation) (16.0)](https://testingbot.com# "iPad Pro (12.9-inch) (5th generation) - 16.0")[iPad Pro (11-inch) (3rd generation) (16.0)](https://testingbot.com# "iPad Pro (11-inch) (3rd generation) - 16.0")[iPad (9th generation) (16.0)](https://testingbot.com# "iPad (9th generation) - 16.0")[iPad Air (5th generation) (16.0)](https://testingbot.com# "iPad Air (5th generation) - 16.0") ![Android Browser Testing](https://testingbot.com/assets/environments/svg/android-1b3d235e17522e2238e1c55b4e9cdd41219f653cd958ea065877d3813f32ffc3.svg) ### Android Emulators #### Phones ##### 16.0 [Pixel 9 (16.0)](https://testingbot.com# "Pixel 9 - 16.0") ##### 15.0 [Pixel 9 (15.0)](https://testingbot.com# "Pixel 9 - 15.0") ##### 14.0 [Pixel 8 (14.0)](https://testingbot.com# "Pixel 8 - 14.0") ##### 13.0 [Pixel 6a (13.0)](https://testingbot.com# "Pixel 6a - 13.0") ##### 12.0 [Pixel 6 (12.0)](https://testingbot.com# "Pixel 6 - 12.0") ##### 11.0 [Galaxy S21 (11.0)](https://testingbot.com# "Galaxy S21 - 11.0") ##### 10.0 [Pixel 3 (10.0)](https://testingbot.com# "Pixel 3 - 10.0")[Galaxy S10 (10.0)](https://testingbot.com# "Galaxy S10 - 10.0") ##### 9.0 [Galaxy S9 (9.0)](https://testingbot.com# "Galaxy S9 - 9.0") ##### 8.0 [Pixel 2 XL (8.0)](https://testingbot.com# "Pixel 2 XL - 8.0") ##### 7.1 [Pixel 2 (7.1)](https://testingbot.com# "Pixel 2 - 7.1")[Nexus 7 (7.1)](https://testingbot.com# "Nexus 7 - 7.1") ##### 6.0 [Nexus S (6.0)](https://testingbot.com# "Nexus S - 6.0")[Nexus 6 (6.0)](https://testingbot.com# "Nexus 6 - 6.0")[Galaxy S6 (6.0)](https://testingbot.com# "Galaxy S6 - 6.0")[Nexus 4 (6.0)](https://testingbot.com# "Nexus 4 - 6.0") ##### 5.0 [Galaxy S5 (5.0)](https://testingbot.com# "Galaxy S5 - 5.0")[Nexus 1 (5.0)](https://testingbot.com# "Nexus 1 - 5.0") ##### 4.4 [Galaxy S4 (4.4)](https://testingbot.com# "Galaxy S4 - 4.4")[Galaxy Nexus (4.4)](https://testingbot.com# "Galaxy Nexus - 4.4") #### Tablets ##### 15.0 [Galaxy Tab S9 (15.0)](https://testingbot.com# "Galaxy Tab S9 - 15.0") ##### 12.0 [Galaxy Tab S7 (12.0)](https://testingbot.com# "Galaxy Tab S7 - 12.0") ##### 11.0 [Galaxy Tab S6 (11.0)](https://testingbot.com# "Galaxy Tab S6 - 11.0") ##### 10.0 [Galaxy Tab S5 (10.0)](https://testingbot.com# "Galaxy Tab S5 - 10.0") ##### 9.0 [Galaxy Tab S4 (9.0)](https://testingbot.com# "Galaxy Tab S4 - 9.0") ##### 8.0 [Pixel C (8.0)](https://testingbot.com# "Pixel C - 8.0") #### Chromeos ##### 14.0 [ChromeOS Medium (14.0)](https://testingbot.com# "ChromeOS Medium - 14.0")[ChromeOS Large (14.0)](https://testingbot.com# "ChromeOS Large - 14.0")[ChromeOS Small (14.0)](https://testingbot.com# "ChromeOS Small - 14.0") --- URL: https://testingbot.com/support/web-automate/selenium # Selenium Examples Run your first Selenium test on the TestingBot browser cloud in no time. Please pick a framework to see examples on how to quickly run your first browser test. ### [NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs) Get started with NodeJS testing frameworks and tools. - [NodeJS](https://testingbot.com/support/web-automate/selenium/nodejs) - [WebdriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) - [TestCafe](https://testingbot.com/support/web-automate/selenium/nodejs/testcafe) - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) - [Jest](https://testingbot.com/support/web-automate/selenium/nodejs/jest) ### [Java](https://testingbot.com/support/web-automate/selenium/java) Get started with Java testing frameworks and tools. - [Java](https://testingbot.com/support/web-automate/selenium/java) - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) - [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide) - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) ### [Python](https://testingbot.com/support/web-automate/selenium/python) Get started with Python testing frameworks and tools. - [Python](https://testingbot.com/support/web-automate/selenium/python) - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) - [SeleniumBase](https://testingbot.com/support/web-automate/selenium/python/seleniumbase) ### [.NET](https://testingbot.com/support/web-automate/selenium/csharp) Get started with .NET testing frameworks and tools. - [C#](https://testingbot.com/support/web-automate/selenium/csharp) - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) ### [PHP](https://testingbot.com/support/web-automate/selenium/php) Get started with PHP testing frameworks and tools. - [PHP](https://testingbot.com/support/web-automate/selenium/php) - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) - [Laravel-Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) ### [Ruby](https://testingbot.com/support/web-automate/selenium/ruby) Get started with Ruby testing frameworks and tools. - [Ruby](https://testingbot.com/support/web-automate/selenium/ruby) - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) ### [JavaScript](https://testingbot.com/support/web-automate/selenium/javascript) Get started with JavaScript testing frameworks and tools. - [JavaScript](https://testingbot.com/support/web-automate/selenium/javascript) - [Intern](https://testingbot.com/support/web-automate/selenium/javascript/intern) - [Karma](https://testingbot.com/support/web-automate/selenium/javascript/karma) ### [Appium](https://testingbot.com/support/web-automate/mobile) Get started with mobile web testing using Appium. - [Appium Examples](https://testingbot.com/support/web-automate/mobile) ![Robot Framework Testing example](https://testingbot.com/assets/wizard/robotframework-08821f4942343bcb1f828470b5cbff3163369c14884b7ca285be190017ee7a94.png) ### [Robot Framework](https://testingbot.com/support/web-automate/selenium/robotframework) Get started with Robot Framework test automation. - [RobotFramework Examples](https://testingbot.com/support/web-automate/selenium/robotframework) ### Other Get started with other testing tools and IDEs. - [Selenium IDE](https://testingbot.com/support/web-automate/selenium/ide) - [Katalon Studio](https://testingbot.com/support/web-automate/selenium/katalon-studio) - [Oxygen](https://testingbot.com/support/web-automate/selenium/oxygen) --- URL: https://testingbot.com/support/web-automate/selenium/annotating-tests # Updating Tests with Selenium You can use the TestingBot API to send various test information back to TestingBot: test-name, passed/failed state, build identifier and more. We've added custom [JavaScript Executor](https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html) commands which allow you to send back test meta-data to TestingBot, while your test is running. Below are some examples on how to do this in various programming languages: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script('tb:test-name=My test') driver.execute_script('tb:test-result=passed') ((JavascriptExecutor)driver).executeScript("tb:test-name=My test"); ((JavascriptExecutor)driver).executeScript("tb:test-result=passed"); $web_driver->executeScript('tb:test-name=My test'); $web_driver->executeScript('tb:test-result=passed'); driver.execute_script('tb:test-name=My test') driver.execute_script('tb:test-result=passed') driver.executeScript('tb:test-name=My test') driver.executeScript('tb:test-result=passed') ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-name=My test"); ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=passed"); ## Set a test name tb:test-name=My Test Name Sets the test-name for the currently running test. This name will be visible on TestingBot. ## Break test tb:break This will add a breakpoint to the test and pause it, so that you can investigate it manually. When you go to the test result page on TestingBot, a live session will appear so that you can debug with mouse and keyboard. ## Test Result tb:test-result=true Possible values: passed, true, failed, false This will set the test as passed (`"passed"` or `true`) or failed (`"failed"` or `false`) on TestingBot. ## Test Build tb:test-build=my build Sets the test's build name. ## Test Tags tb:test-tags=tag1,tag2 comma-separated list of tags Sets the test's tags. ## Test Context tb:test-context=my context Logs the given context and prints it on the TestingBot test result page, in the Selenium command list. ## Test Info tb:test-info={'build':'my first build', 'name':'my new test', 'public':true} JSON-formatted dictionary with optional keys: `'build'`, `'name'`, `'public'`, `'status_message'`, `'extra'` Pass in a JSON dictionary with various fields to update the test's meta-data on TestingBot. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/capabilities # Selenium Capabilities Generator Generate Selenium capabilities for your automated tests. Choose your browser, OS and configuration options to get the exact code you need for Java, Python, NodeJS, C#, Ruby or PHP. [![Selenium capabilities](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)Selenium](https://testingbot.com/support/web-automate/selenium/capabilities)[![Appium capabilities](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium/capabilities)[![Puppeteer capabilities](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer/capabilities)[![Playwright capabilities](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)Playwright](https://testingbot.com/support/web-automate/playwright/capabilities) Browser Environment ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Resolution800x6001024x7681280x8001280x9601280x10241440x9001680x10501600x12001920x12001920x10802560x1440 Selenium Version4.39.04.38.04.37.04.36.04.35.04.34.04.33.04.32.04.31.04.30.04.29.04.28.14.28.04.27.04.26.04.25.04.24.04.23.14.23.04.22.04.21.04.20.04.19.04.18.14.18.04.17.04.16.14.16.04.15.04.14.14.14.04.13.04.12.14.12.04.11.04.10.04.9.04.8.34.8.24.8.14.8.04.7.04.6.04.5.34.5.24.5.14.5.04.4.04.3.04.2.24.2.14.2.04.1.34.1.24.1.14.1.04.0.04.0.0-beta-44.0.0-beta-34.0.0-beta-24.0.0-beta-14.0.0-alpha-74.0.0-alpha-63.141.593.141.53.141.03.14.03.13.03.12.03.11.03.10.03.9.03.8.13.8.03.7.13.7.03.6.03.5.33.5.23.5.13.5.03.4.03.3.13.3.03.2.03.1.03.0.12.53.12.53.02.52.02.51.02.50.02.49.02.48.22.48.12.48.0 ## Project Capabilities Test NameAllows you to customize the name of the test, as it will appear in the dashboard. Build NameGroup tests under the same build identifier for easy retrieval. ## Debugging Record Video YesNo Take Screenshot After Each Step YesNo Collect Logs YesNo ## Customization Headless ModeRun the browser without rendering UI for faster test execution. YesNo Geolocation TestingRun the test from a different geographical location.NoneRandom CountryAustraliaBahrainBelgiumBrazilCanadaChileFranceGermanyIndiaItalyJapanNorwaySingaporeSouth AfricaSwedenSwitzerlandUnited Arab EmiratesUnited KingdomUnited States Timezone ([list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) Prerun Script ([documentation](https://testingbot.com/support/web-automate/selenium/test-options#prerun)) Upload URLs Looking for more options? See [all Selenium capabilities](https://testingbot.com/support/web-automate/selenium/test-options). W3C Protocol W3C is the newest WebDriver protocol, TestingBot recommends using W3C. JSONWP JSONWP is the legacy protocol which is no longer actively maintained. JavaPythonNodeJSC#RubyPHP MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, "chrome"); capabilities.setCapability(CapabilityType.BROWSER_VERSION, "latest"); capabilities.setCapability(CapabilityType.PLATFORM_NAME, "Windows 11"); --- URL: https://testingbot.com/support/web-automate/selenium/performance # Performance Testing Documentation With this call, you can fetch various performance metrics from the browser, during your test. With this functionality, you can create tests where you monitor specific pageload time, or any other metric. If the metric is below a specific threshold that you define, you can make the test fail. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script("tb:performance") ((JavascriptExecutor) driver).executeScript("tb:performance"); $driver->executeScript("tb:performance"); driver.execute_script("tb:performance") browser.execute('tb:performance') ((IJavaScriptExecutor)driver).ExecuteScript("tb:performance"); #### Response: | `pageSize (bytes)` | The size (in bytes) of the page (HTML source). | | `nrRequests` | How many requests the page made (AJAX/images/...) | | `load (ms)` | The pageload time of the webpage. ​​​The time it takes for a page to download and diplsay the entire web page. | | `domContentLoaded (ms)` | The domContentLoaded duration of the page. The DOMContentLoaded event fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. [DOMContentLoaded Info](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) | | `firstMeaningfulPaint (ms)` | Indicates how fast your page displays its primary content. [firstMeaningfulPaint Info](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint) | | `firstPaint (ms)` | First Paint is triggered when a render (any render) is detected in the browser. | | `firstContentfulPaint (ms)` | First Contentful Paint measures the time from navigation to the time when the browser renders the first bit of content from the DOM. [firstContentfulPaint Info](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint) | #### Example Response: { "pageSize" => 396800, "nrRequests" => 20, "load" => 1378, "domContentLoaded" => 585, "firstMeaningfulPaint" => 0, "firstPaint" => 348, "firstContentfulPaint" => 348 } #### Sample UseCase: This example demonstrates a test that visits a page, checks the performance and fails the test if the performance is not sufficient. require "rubygems" require "selenium-webdriver" require "selenium/client" caps = { :browserName => "chrome", :version => "latest", :platform => "WIN10", :debugging => true } urlhub = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub" client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 120 @webdriver = Selenium::WebDriver.for :remote, :url => urlhub, :desired_capabilities => caps, :http_client => client @webdriver.navigate.to "https://testingbot.com/" performance = @webdriver.execute_script("tb:performance") assert performance["load"] < 900 @webdriver.quit Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/uploads # Uploading with Selenium With Selenium WebDriver it's possible to test file uploads. You can either specify a file that needs to be uploaded at the [start of your test](https://testingbot.com#before), or upload the file [during your test](https://testingbot.com#during). ## 1. Upload a file before your test starts With TestingBot you can specify a URL in your desired capabilities which links to the file you want to be present on our test VMs. TestingBot will then first download the URL and save it on the test VM so your test can use the file. You specify the download URL as `upload` and use `uploadFilepath` in your desired capabilities to indicate where TestingBot needs to put the file. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require "test/unit" require 'selenium-webdriver' class UploadTest < Test::Unit::TestCase def setup caps = Selenium::WebDriver::Remote::Capabilities.chrome caps.version = "latest" caps.platform = "WIN10" caps[:name] = "Test File Upload" caps[:upload] = "https://testingbot.com/assets/logo-head.png" caps[:uploadFilepath] = "C:\\test\\logo.png" # use C:\test\filename.ext on Windows and /tmp/filename.ext on Linux/OSX @driver = Selenium::WebDriver.for( :remote, :url => "https://key:secret@hub.testingbot.com/wd/hub", :desired_capabilities => caps) end def test_upload @driver.navigate.to "http://the-internet.herokuapp.com/upload" element = @driver.find_element(:id, 'file-upload') element.send_keys "C:\\test\\logo.png" # use C:\test on Windows and /tmp on Linux/OSX @driver.find_element(:id, "file-submit").click assert "logo.png" == @driver.find_element(:id, "uploaded-files").text end def teardown @driver.quit end end import org.openqa.selenium.By; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; public class JavaSample { public static final String URL = "https://key:secret@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("platform", "WIN10"); caps.setCapability("version", "latest"); caps.setCapability("name", "Test File Upload"); caps.setCapability("upload", "https://testingbot.com/assets/logo-head.png"); caps.setCapability("uploadFilepath", "C:\\test\\logo.png"); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.setFileDetector(new LocalFileDetector()); driver.get("http://the-internet.herokuapp.com/upload"); driver.findElement(By.id("file-upload")).sendKeys("C:\\test\\logo.png"); driver.findElement(By.id("file-submit")).click(); driver.quit(); } } get("http://the-internet.herokuapp.com/upload"); $file_input = $driver->findElement(WebDriverBy::id("file-upload")); $file_input->setFileDetector(new LocalFileDetector()); $file_input->sendKeys("C:\\test\\logo.png"); $driver->findElement(WebDriverBy::id("file-submit"))->click(); sleep(5); $driver->quit(); ?> from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities desired_caps = { 'browserName': 'chrome', 'version': 'latest', 'platform': 'WIN10', 'name': 'Test File Upload', 'upload': 'https://testingbot.com/assets/logo-head.png', 'uploadFilepath': 'C:\\test\\logo.png' } driver = webdriver.Remote( command_executor='https://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) driver.get('http://the-internet.herokuapp.com/upload') driver.find_element_by_id('file-upload').send_keys('C:\\test\\logo.png') driver.find_element_by_id('file-submit').click() driver.quit() var webdriver = require('selenium-webdriver'); var remote = require('selenium-webdriver/remote'); var capabilities = { 'browserName': 'chrome', 'version': 'latest', 'platform': 'WIN10', 'name': 'Test File Upload', 'upload': 'https://testingbot.com/assets/logo-head.png', 'uploadFilepath': 'C:\\test\\logo.png', 'client_key': 'key', 'client_secret': 'secret' }; var driver = new webdriver.Builder(). usingServer('https://hub.testingbot.com/wd/hub'). withCapabilities(capabilities). build(); var fs = require('fs'); webdriver.WebDriver.prototype.saveScreenshot = function(filename) { return driver.takeScreenshot().then(function(data) { fs.writeFile(filename, data.replace(/^data:image\/png;base64,/,''), 'base64', function(err) { if(err) throw err; }); }) }; driver.setFileDetector(new remote.FileDetector); driver.get('http://the-internet.herokuapp.com/upload').then(function(){ driver.findElement(webdriver.By.id('file-upload')).sendKeys('C:\\test\\logo.png').then(function(){ driver.findElement(webdriver.By.id('file-submit')).click().then(function(){ driver.getTitle().then(function(title) { console.log(title); driver.quit(); }); }); }); }); using System; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using System.Text; namespace SeleniumTest { class Program { static void Main(string[] args) { IWebDriver driver; ChromeOptions capability = new ChromeOptions(); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("client_key", "key", true); capability.AddAdditionalCapability("client_secret", "secret", true); capability.AddAdditionalCapability("name", "Test File Upload", true); capability.AddAdditionalCapability("upload", "https://testingbot.com/assets/logo-head.png", true); capability.AddAdditionalCapability("uploadFilepath", "C:\\test\\logo.png", true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), capability); driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/upload"); var allowsDetection = driver as IAllowsFileDetection; allowsDetection.FileDetector = new LocalFileDetector(); IWebElement upload = driver.FindElement(By.Id("file-upload")); upload.SendKeys("C:\\test\\logo.png"); driver.FindElement(By.Id("file-submit")).Click(); driver.Quit(); } } } ## 2. Upload a file during your test You can use `LocalFileDetector` to upload a file from your local computer to the remote VM/device during your test. In the example below, we'll upload an image, residing on your own computer `/Users/test/logo.png`, via the remote VM/device in the TestingBot cloud to a website. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require "test/unit" require 'selenium-webdriver' class UploadTest < Test::Unit::TestCase def setup caps = Selenium::WebDriver::Remote::Capabilities.chrome caps.version = "latest" caps.platform = "WIN10" caps[:name] = "Test File Upload" @driver = Selenium::WebDriver.for( :remote, :url => "https://key:secret@hub.testingbot.com/wd/hub", :desired_capabilities => caps) end def test_upload @driver.navigate.to "http://the-internet.herokuapp.com/upload" element = @driver.find_element(:id, 'file-upload') element.send_keys "/Users/test/logo.png" @driver.find_element(:id, "file-submit").click assert "logo.png" == @driver.find_element(:id, "uploaded-files").text end def teardown @driver.quit end end import org.openqa.selenium.By; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; public class JavaSample { public static final String URL = "https://key:secret@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("platform", "WIN10"); caps.setCapability("version", "latest"); caps.setCapability("name", "Test File Upload"); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.setFileDetector(new LocalFileDetector()); driver.get("http://the-internet.herokuapp.com/upload"); driver.findElement(By.id("file-upload")).sendKeys("/Users/test/logo.png"); driver.findElement(By.id("file-submit")).click(); driver.quit(); } } get("http://the-internet.herokuapp.com/upload"); $file_input = $driver->findElement(WebDriverBy::id("file-upload")); $file_input->setFileDetector(new LocalFileDetector()); $file_input->sendKeys("/Users/test/logo.png"); $driver->findElement(WebDriverBy::id("file-submit"))->click(); sleep(5); $driver->quit(); ?> from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities desired_caps = { 'browserName': 'chrome', 'version': 'latest', 'platform': 'WIN10', 'name': 'Test File Upload' } driver = webdriver.Remote( command_executor='https://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) driver.get('http://the-internet.herokuapp.com/upload') driver.find_element_by_id('file-upload').send_keys('/Users/test/logo.png') driver.find_element_by_id('file-submit').click() driver.quit() const webdriver = require('selenium-webdriver'); const fs = require('fs'); const remote = require('selenium-webdriver/remote'); const capabilities = { 'browserName': 'chrome', 'version': 'latest', 'platform': 'WIN10', 'name': 'Test File Upload', 'client_key': 'key', 'client_secret': 'secret' }; const driver = new webdriver.Builder(). usingServer('https://hub.testingbot.com/wd/hub'). withCapabilities(capabilities). build(); webdriver.WebDriver.prototype.saveScreenshot = function(filename) { return driver.takeScreenshot().then(function(data) { fs.writeFile(filename, data.replace(/^data:image\/png;base64,/,''), 'base64', function(err) { if(err) throw err; }); }) }; driver.setFileDetector(new remote.FileDetector); driver.get('http://the-internet.herokuapp.com/upload').then(function(){ driver.findElement(webdriver.By.id('file-upload')).sendKeys('/Users/test/logo.png').then(function(){ driver.findElement(webdriver.By.id('file-submit')).click().then(function(){ driver.getTitle().then(function(title) { console.log(title); driver.quit(); }); }); }); }); using System; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using System.Text; namespace SeleniumTest { class Program { static void Main(string[] args) { IWebDriver driver; ChromeOptions capability = new ChromeOptions(); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("client_key", "key", true); capability.AddAdditionalCapability("client_secret", "secret", true); capability.AddAdditionalCapability("name", "Test File Upload", true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), capability); driver.Navigate().GoToUrl("http://the-internet.herokuapp.com/upload"); var allowsDetection = driver as IAllowsFileDetection; allowsDetection.FileDetector = new LocalFileDetector(); IWebElement upload = driver.FindElement(By.Id("file-upload")); upload.SendKeys("/Users/test/logo.png"); driver.FindElement(By.Id("file-submit")).Click(); driver.Quit(); } } } ## TestingBot Storage With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your files on our servers. The advantage of this is that our test VMs can immediately download your file from our own network, which is much faster than downloading from the public internet. To upload your file with TestingBot Storage, please see [the API upload examples](https://testingbot.com/support/api#upload). An example of using the uploaded file via TestingBot Storage: require 'rubygems' require "test/unit" require 'selenium-webdriver' class UploadTest < Test::Unit::TestCase def setup caps = Selenium::WebDriver::Remote::Capabilities.firefox caps.version = "latest" caps.platform = :WINDOWS caps[:name] = "Test File Upload" caps[:upload] = "tb://....." # the unique hash you got back from TestingBot Storage caps[:uploadFilepath] = "C:\\test\\file.ext" # use C:\test\filename.ext on Windows and /tmp/filename.ext on Linux/OSX @driver = Selenium::WebDriver.for( :remote, :url => "https://key:secret@hub.testingbot.com/wd/hub", :desired_capabilities => caps) end def test_upload @driver.navigate.to "http://the-internet.herokuapp.com/upload" element = @driver.find_element(:id, 'file-upload') element.send_keys "C:\\test\\logo.png" # use C:\test on Windows and /tmp on Linux/OSX @driver.find_element(:id, "file-submit").click assert "logo.png" == @driver.find_element(:id, "uploaded-files").text end def teardown @driver.quit end end Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/test-options # Selenium Test Options This page offers an overview of all the various options you can specify when starting an automated Selenium test. The **Selenium-Specific Settings** are required to run automated Selenium tests: `browserName`, `browserVersion` and `platformName`. The other options are **TestingBot Options** , these allow you to customize your test in terms of specific driver versions, privacy options, platform options and more. The [Selenium Capabilities generator](https://testingbot.com/support/web-automate/selenium/capabilities) allows you to easily generate the necessary capabilities for your tests. ## Required Selenium Settings ### Browser Name The name of the browser to run your automated test on. Please see our [list of browsers](https://testingbot.com/support/web-automate/browsers) that we support. The `browserName` is a required field that needs to be passed to us via Selenium's [Desired Capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "chrome" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); $caps = array( "browserName" => "chrome" ); capabilities = { "browserName" : "chrome" } const capabilities = { "browserName" : "chrome" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("browserName", "chrome"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { browserName: "chrome" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'browserName': "chrome", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Browser Version The version of the browser to run your automated test on. Please see our [list of browsers + versions](https://testingbot.com/support/web-automate/browsers) that we support. The `version` is a required field that needs to be passed to us via Selenium's [Desired Capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["version"] = "81" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("version", "81"); $caps = array( "version" => "81" ); capabilities = { "version" : "81" } const capabilities = { "version" : "81" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("version", "81"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { browserName: "chrome", browserVersion: "106" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("browserVersion", "81"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setVersion(81); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'browserName': "chrome", 'browserVersion': '81', 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "browserVersion": "81", /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Other Options: - `"version": "*"` : If you use `*` as version, TestingBot will pick a random version. - `"version": "latest"` : TestingBot will automatically take the latest version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions. For example, if the current latest Firefox version is 81 and you use `latest-2`, then the test will run on Firefox 79. - `"version": "<=16"` : TestingBot will pick a version smaller than or equal to the version you specify with `<=`. `"version": "16>="` : TestingBot will pick a version higher than or equal to the version you specify with `>=`. ### Platform Indicates on which operating system the test should run. Please see a [list of platforms](https://testingbot.com/support/web-automate/browsers) that we currently support. The `platform` is a required field that needs to be passed to us via Selenium's [Desired Capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["platform"] = "Windows 10" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("platform", "Windows 10"); $caps = array( "platform" => "Windows 10" ); capabilities = { "platform" : "Windows 10" } const capabilities = { "platform" : "Windows 10" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("platform", "Windows 10"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platform_name: "Windows 10" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Device Name When running a mobile automated test, you'll need to specify on which [mobile device](https://testingbot.com/support/app-automate/devices) (or [simulator/emulator](https://testingbot.com/support/web-automate/browsers)) you want to test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "Samsung S21" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); caps.setCapability("appium:deviceName", "Samsung S23"); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "Samsung S21", 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "appium:deviceName": 'Samsung S23', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["appium:deviceName"] = "Samsung S23" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); We offer regex/wildcard parameters which you can use to allocate a device: | Regex Input | Result | | --- | --- | | `"iPhone.*"` | This will allocate any available iPhone device (phone) | | `".*Galaxy.*"` | This will allocate any of the available Galaxy devices (phone or tablet) | | `"*"` | This will allocate a random available device, either iOS or Android device | | `"iPhone [8-11]"` | This will allocate either an iPhone 8 or 11 | | `"iPhone 6.*"` | This will allocate either an iPhone 6 or 6S | Some Examples: // find any iPhone, except 6 or 6s capabilities.setCapability("appium:deviceName", "^(iPhone.*)(?!6|6S)$"); // find any device which name starts with Samsung capabilities.setCapability("appium:deviceName", "Samsung.*"); ### Device Version You can specify the version of the device you want to target. In case of physical devices, you might want to use regex/wildcard patterns to target a broad range of devices. This way your chance of hitting an occupied device during your automated test decreases significantly. Instead of only targetting a specific iOS or Android device, you can target a wider range of devices. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { version: "(16|17).*" } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("appium:platformName", "Android"); caps.setCapability("appium:deviceName", "*"); caps.setCapability("tb:options", tbOptions); caps.setCapability("appium:version", "(13|14).*"); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'appium:deviceName': "*", 'appium:version': '(13|14).*' 'platformName': "Android", 'goog:chromeOptions': {'w3c': True} } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "appium:deviceName": '*', "appium:version": '(13|14).*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android" }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*" ["version"] = "(13|14).*" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Some Examples: // target multiple specific versions of an iPhone device capabilities.setCapability("appium:deviceName", "iPhone.*"); capabilities.setCapability("appium:version", "15.0|14.2|14|13.4|13.3"); // find any Samsung device with Android version 13 or 14 capabilities.setCapability("appium:deviceName", "Samsung.*"); capabilities.setCapability("appium:version", "(13|14).*"); ### Tablet Only You can specify this capability when you only want to allocate a tablet device. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "*", tabletOnly: true } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("tabletOnly", true); tbOptions.setCapability("deviceName", "*"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "*", 'tabletOnly': true, 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "deviceName": '*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "tabletOnly": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*", ["tabletOnly"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Phone Only You can specify this capability when you only want to allocate a phone device. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { deviceName: "*", phoneOnly: true } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("phoneOnly", true); tbOptions.setCapability("deviceName", "*"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Android"); caps.setCapability("tb:options", tbOptions); tbOptions = { 'name': 'W3C Sample' } chromeOpts = { 'deviceName': "*", 'phoneOnly': true, 'platformName': "Android", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "deviceName": '*', "platformName": 'Android', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "phoneOnly": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { PlatformName = "Android", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["deviceName"] = "*", ["phoneOnly"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Use a specific version of Selenium By default we use Selenium version `2.53.1` to run your test. If you wish to use another Selenium version for your test, please specify one of the following available versions: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["selenium-version"] = '2.53.1' DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("selenium-version", '2.53.1'); $caps = array( "selenium-version" => '2.53.1' ); capabilities = { "selenium-version" : '2.53.1' } const capabilities = { "selenium-version" : '2.53.1' } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("selenium-version", '2.53.1'); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "selenium-version" : '2.53.1' } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("selenium-version", '2.53.1'); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'selenium-version' => '2.53.1' )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'selenium-version': '2.53.1' } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "selenium-version": '2.53.1' } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["selenium-version"] = "2.53.1" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | "2.53.1" | 4.39.0 4.38.0 4.37.0 4.36.0 4.35.0 4.34.0 4.33.0 4.32.0 4.31.0 4.30.0 4.29.0 4.28.1 4.28.0 4.27.0 4.26.0 4.25.0 4.24.0 4.23.1 4.23.0 4.22.0 4.21.0 4.20.0 4.19.0 4.18.1 4.18.0 4.17.0 4.16.1 4.16.0 4.15.0 4.14.1 4.14.0 4.13.0 4.12.1 4.12.0 4.11.0 4.10.0 4.9.0 4.8.3 4.8.2 4.8.1 4.8.0 4.7.0 4.6.0 4.5.3 4.5.2 4.5.1 4.5.0 4.4.0 4.3.0 4.2.2 4.2.1 4.2.0 4.1.3 4.1.2 4.1.1 4.1.0 4.0.0 4.0.0-beta-4 4.0.0-beta-3 4.0.0-beta-2 4.0.0-beta-1 4.0.0-alpha-7 4.0.0-alpha-6 3.141.59 3.141.5 3.141.0 3.14.0 3.13.0 3.12.0 3.11.0 3.10.0 3.9.0 3.8.1 3.8.0 3.7.1 3.7.0 3.6.0 3.5.3 3.5.2 3.5.1 3.5.0 3.4.0 3.3.1 3.3.0 3.2.0 3.1.0 3.0.1 2.53.1 2.53.0 2.52.0 2.51.0 2.50.0 2.49.0 2.48.2 2.48.1 2.48.0 | ### Chromedriver We support using custom ChromeDriver versions during your tests. By default the most recent Chromedriver is used according to the version of Chrome you're testing on. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["chromedriverVersion"] = "76.0.3809.25" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("chromedriverVersion", "76.0.3809.25"); $caps = array( "chromedriverVersion" => "76.0.3809.25" ); capabilities = { "chromedriverVersion" : "76.0.3809.25" } const capabilities = { "chromedriverVersion" : "76.0.3809.25" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("chromedriverVersion", "76.0.3809.25"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "chromedriverVersion" : "76.0.3809.25" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("chromedriverVersion", "76.0.3809.25"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'chromedriverVersion' => "76.0.3809.25" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'chromedriverVersion': "76.0.3809.25" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "chromedriverVersion": "76.0.3809.25" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10" }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["chromedriverVersion"] = "76.0.3809.25" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | "2.46" | dev 141.0.7390.54 140.0.7339.80 139.0.7207.2 138.0.7153.0 137.0.7117.2 136.0.7064.0 135.0.6999.2 134.0.6958.2 133.0.6943.16 132.0.6811.2 131.0.6778.3 130.0.6669.2 129.0.6614.3 128.0.6613.18 127.0.6533.88 127.0.6485.0 126.0.6423.2 125.0.6422.4 124.0.6367.60 124.0.6356.2 123.0.6262.5 122.0.6253.3 121.0.6154.0 121.0.6129.0 120.0.6099.5 119.0.6045.9 118.0.5979.0 117.0.5938.0 116.0.5845.82 115.0.5790.170 115.0.5790.90 114.0.5735.90 114.0.5735.16 113.0.5672.63 113.0.5672.24 112.0.5615.49 112.0.5615.28 111.0.5563.64 111.0.5563.41 111.0.5563.19 110.0.5481.77 110.0.5481.30 109.0.5414.74 109.0.5414.25 108.0.5359.71 108.0.5359.22 107.0.5304.62 107.0.5304.18 106.0.5249.61 106.0.5249.21 105.0.5195.52 105.0.5195.19 104.0.5112.79 104.0.5112.29 104.0.5112.20 103.0.5060.134 103.0.5060.24 102.0.5005.61 102.0.5005.27 101.0.4951.41 101.0.4951.15 100.0.4896.60 100.0.4896.20 99.0.4844.51 99.0.4844.35 99.0.4844.17 98.0.4758.80 98.0.4758.48 97.0.4692.71 97.0.4692.36 97.0.4692.20 96.0.4664.45 95.0.4638.10 94.0.4606.41 93.0.4577.15 92.0.4515.43 91.0.4472.101 91.0.4472.19 90.0.4430.24 89.0.4389.23 88.0.4324.96 88.0.4324.27 87.0.4280.88 87.0.4280.20 86.0.4240.22 85.0.4183.87 85.0.4183.83 85.0.4183.38 84.0.4147.30 83.0.4103.39 83.0.4103.14 81.0.4044.69 81.0.4044.20 80.0.3987.16 79.0.3945.36 79.0.3945.16 78.0.3904.70 78.0.3904.11 77.0.3865.40 77.0.3865.10 76.0.3809.68 76.0.3809.25 76.0.3809.12 75.0.3770.140 75.0.3770.90 75.0.3770.8 74.0.3729.6 73.0.3683.68 73.0.3683.20 72.0.3626.7 72.0.3626.69 71.0.3578.80 71.0.3578.33 71.0.3578.30 71.0.3578.137 70.0.3538.97 70.0.3538.67 70.0.3538.16 2.46 2.45 2.44 2.43 2.42 2.41 2.40 2.39 2.38 2.37 2.36 2.35 2.34 2.33 2.32 2.31 2.30 2.29 2.28 2.27 2.26 2.25 2.24 2.23 2.22 2.21 2.20 2.19 2.16 2.15 2.14 2.13 2.12 2.10 | ### Internet Explorer Driver (IEDriver) We provide both 32-bit and 64-bit versions of the Internet Explorer driver. By default we use the 2.53.1 (32-bit) IEDriver for your tests. We use 32-bit because of a [slow text entry bug](https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/5116) with the 64-bit version. For our screenshots, we use the 64-bit version, because of a [screenshot problem](https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/5876) with the 32-bit version. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["iedriverVersion"] = "2.53.1" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("iedriverVersion", "2.53.1"); $caps = array( "iedriverVersion" => "2.53.1" ); capabilities = { "iedriverVersion" : "2.53.1" } const capabilities = { "iedriverVersion" : "2.53.1" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("iedriverVersion", "2.53.1"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "internet explorer", browserVersion: "latest", "se:ieOptions": {}, "tb:options": { "iedriverVersion" : "4.8.0", "selenium-version": "4.8.0" } } InternetExplorerOptions ieOpts = new InternetExplorerOptions(); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("iedriverVersion", "4.8.0"); tbOptions.setCapability("selenium-version", "4.8.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("se:ieOptions", ieOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "internet explorer"); $capabilities = DesiredCapabilities::internetExplorer(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'iedriverVersion' => "4.8.0", 'selenium-version' => "4.8.0" )); $capabilities->setCapability('se:ieOptions', []); tbOptions = { 'name': 'W3C Sample', 'iedriverVersion': '4.8.0', 'selenium-version': '4.8.0' } ieOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'se:ieOptions': {}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=ieOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'internet explorer', "platformName": 'Windows 10', "se:ieOptions" : {}, "tb:options": { "key": "api_key", "secret": "api_secret", "iedriverVersion": "4.8.0", "selenium-version": "4.8.0" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var ieOptions = new InternetExplorerOptions() { BrowserVersion = "11", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["iedriverVersion"] = "4.8.0", ["selenium-version"] = "4.8.0" }; ieOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), ieOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | 2.53.1 | x64\_4.14.0 4.14.0 x64\_4.11.0 4.11.0 x64\_4.10.0 4.10.0 x64\_4.8.1 4.8.1 x64\_4.8.0 4.8.0 x64\_4.7.0 4.7.0 x64\_4.6.0 4.6.0 x64\_4.3.0 4.3.0 x64\_4.2.0 4.2.0 x64\_4.0.0 4.0.0 x64\_3.141.59 3.141.59 x64\_3.141.5 3.141.5 x64\_3.141.0 3.141.0 x64\_3.14.0 3.14.0 x64\_3.13.0 3.13.0 x64\_3.12.0 3.12.0 x64\_3.11.1 3.11.1 x64\_3.11.0 3.11.0 x64\_3.10.0 3.10.0 x64\_3.9.0 3.9.0 x64\_3.8.0 3.8.0 x64\_3.7.0 3.7.0 x64\_3.6.0 3.6.0 x64\_3.5.0 3.5.0 x64\_3.4.0 3.4.0 x64\_3.3.0 3.3.0 x64\_3.2.0 3.2.0 x64\_3.1.0 3.1.0 x64\_2.53.1 2.53.1 x64\_2.53.0 2.53.0 x64\_2.52.2 2.52.2 x64\_2.51.0 2.51.0 x64\_2.50.0 2.50.0 x64\_2.49.0 2.49.0 x64\_2.48.0 2.48.0 x64\_2.47.0 2.47.0 x64\_2.46.0 2.46.0 x64\_2.45.0 2.45.0 x64\_2.42.0 2.42.0 | ### Edge Driver (MicrosoftWebDriver) EdgeDriver is built by Microsoft to automate the Microsoft Edge Browser. By default, we make sure that the most recent fully-compatible EdgeDriver is used for every test running on the Microsoft Edge Browser. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { "browserName" : "MicrosoftEdge", "platform": "WINDOWS" } caps["edgedriverVersion"] = "110" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("edgedriverVersion", "110"); $caps = array( "edgedriverVersion" => "110" ); capabilities = { "edgedriverVersion" : "110" } const capabilities = { "edgedriverVersion" : "110", "ms:edgeOptions": {} } var edgeOptions = new EdgeOptions() { BrowserVersion = "11", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["edgeDriverVersion"] = "110", ["selenium-version"] = "4.8.0" }; edgeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), edgeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "microsoftedge", browserVersion: "latest", "tb:options" => { "edgedriverVersion" : "110" }, "ms:edgeOptions": {} } EdgeOptions edgeOpts = new EdgeOptions(); edgeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("edgedriverVersion", "110"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(EdgeOptions.CAPABILITY, edgeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new EdgeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'edgedriverVersion' => "110" )); $capabilities->setCapability('ms:edgeOptions', array()); $capabilities->setCapability(EdgeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'edgedriverVersion': '110' } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'tb:options': tbOptions, 'ms:edgeOptions': '' } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) let driver = await new webdriver.Builder().withCapabilities({ "browserName": 'microsoftedge', "platformName": 'Windows 10', "ms:edgeOptions" : {}, "tb:options": { "key": "api_key", "secret": "api_secret", "edgedriverVersion": "110" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var edgeOptions = new EdgeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["edgedriverVersion"] = "110" }; edgeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), edgeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | 15063 | 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 81 dev insiders 16299 15063 14393 | ### Firefox Driver (Geckodriver) For Firefox 47 and up, webdriver tests on Firefox need to use [Mozilla's GeckoDriver](https://github.com/mozilla/geckodriver). Specify this option to choose which Geckodriver we should use. By default, we use the version that is most compatible with the Firefox version you request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["geckodriverVersion"] = "0.28.0" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("geckodriverVersion", "0.28.0"); $caps = array( "geckodriverVersion" => "0.28.0" ); capabilities = { "geckodriverVersion" : "0.28.0" } const capabilities = { "geckodriverVersion" : "0.28.0" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("geckodriverVersion", "0.28.0"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "firefox", browserVersion: "latest", "tb:options": { "geckodriverVersion" : "0.28.0" }, "moz:firefoxOptions": {} } FirefoxOptions ffOptions = new FirefoxOptions(); ffOptions.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("geckodriverVersion", "0.28.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(FirefoxOptions.CAPABILITY, ffOptions); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "firefox"); $options = new FirefoxOptions(); $capabilities = DesiredCapabilities::firefox(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'geckodriverVersion' => "0.28.0" )); $capabilities->setCapability('moz:firefoxOptions', array()); $capabilities->setCapability(FirefoxOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'geckodriverVersion': "0.28.0" } chromeOpts = { 'browserName': "firefox", 'platformName': "Windows 10", 'tb:options': tbOptions, 'moz:firefoxOptions': {} } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'firefox', "platformName": 'Windows 10', "tb:options": { "key": "api_key", "secret": "api_secret", "geckodriverVersion": "0.28.0" }, 'moz:firefoxOptions': {} }).usingServer("https://hub.testingbot.com/wd/hub").build(); var ffOptions = new FirefoxOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["geckodriverVersion"] = "0.28.0" }; ffOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), ffOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | 0.28.0 | 0.36.0 0.35.0 0.34.0 0.33.0 0.32.2 0.32.1 0.32.0 0.31.0 0.30.0 0.29.1 0.29.0 0.28.0 0.27.0 0.26.0 0.25.0 0.24.0 0.23.0 0.22.0 0.21.0 0.20.1 0.19.1 0.19.0 0.18.0 0.17.0 0.16.1 0.16.0 0.15.0 0.14.0 0.13.0 0.12.0 0.11.0 0.10.0 0.9.0 0.8.0 0.7.1 0.6.2 | ### Opera Driver Opera uses the [Chromium OperaDriver](https://github.com/operasoftware/operachromiumdriver/releases) to automate Opera Desktop Browsers. Specify this option to choose which OperaDriver we should use. By default, we use the version that is most compatible with the Opera version you request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["operaDriverVersion"] = "90.0.4430.85" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("operaDriverVersion", "90.0.4430.85"); $caps = array( "operaDriverVersion" => "90.0.4430.85" ); capabilities = { "operaDriverVersion" : "90.0.4430.85" } const capabilities = { "operaDriverVersion" : "90.0.4430.85" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("operaDriverVersion", "90.0.4430.85"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "opera", browserVersion: "latest", "tb:options" => { "operaDriverVersion" : "90.0.4430.85" } } OperaOptions operaOpts = new OperaOptions(); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("operaDriverVersion", "90.0.4430.85"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(OperaOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "opera"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setBrowserName('opera'); $capabilities->setCapability('tb:options', array( 'operaDriverVersion' => "90.0.4430.85" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'operaDriverVersion': "90.0.4430.85" } chromeOpts = { 'browserName': "opera", 'platformName': "Windows 10", 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'opera', "platformName": 'Windows 10', "tb:options": { "key": "api_key", "secret": "api_secret", "operaDriverVersion": "90.0.4430.85" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var operaOptions = new OperaOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["operaDriverVersion"] = "90.0.4430.85" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), operaOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | 87.0.4280.67 | 139.0.7258.156 138.0.7204.251 137.0.7151.122 135.0.7049.115 134.0.6998.205 133.0.6943.143 132.0.6834.209 131.0.6778.86 130.0.6723.137 128.0.6613.162 127.0.6533.120 126.0.6478.127 125.0.6422.143 124.0.6367.62 123.0.6312.59 122.0.6261.95 121.0.6167.140 120.0.6099.200 119.0.6045.124 118.0.5993.89 117.0.5938.132 116.0.5845.97 115.0.5790.171 114.0.5735.110 113.0.5672.127 112.0.5615.87 111.0.5563.65 110.0.5481.100 109.0.5414.120 108.0.5359.99 107.0.5304.88 106.0.5249.119 105.0.5195.102 104.0.5112.81 103.0.5060.66 102.0.5005.61 101.0.4951.64 100.0.4896.127 99.0.4844.51 98.0.4758.82 97.0.4692.71 96.0.4664.45 95.0.4638.54 94.0.4606.61 93.0.4577.63 92.0.4515.107 91.0.4472.77 90.0.4430.85 89.0.4389.82 88.0.4324.104 87.0.4280.67 86.0.4240.80 85.0.4183.102 84.0.4147.89 83.0.4103.97 81.0.4044.113 80.0.3987.100 79.0.3945.79 78.0.3904.87 77.0.3865.120 76.0.3809.132 75.0.3770.100 2.45 2.42 2.41 2.40 2.38 2.37 2.36 2.35 2.33 2.32 2.30 2.229 2.27 2.26 2.25 2.24 2.23 2.22 | ### Taking screenshots during your tests By default we do not capture screenshots at every step of your test. If you wish to take a screenshot for every step, please add this capability (set to `true`) to your request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screenshot"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screenshot", true); $caps = array( "screenshot" => true ); capabilities = { "screenshot" : True } const capabilities = { "screenshot" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screenshot", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { screenshot: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenshot", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'screenshot' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenshot': True } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenshot": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenshot"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | boolean | false | ### Make a video of your tests By default we record a video of your test, which is accessible in the member area. If you do not wish to have this, you can disable it with this option. Video should not slow down your test considerably. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screenrecorder"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screenrecorder", true); $caps = array( "screenrecorder" => true ); capabilities = { "screenrecorder" : True } const capabilities = { "screenrecorder" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screenrecorder", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { screenrecorder: true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screenrecorder", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'screenrecorder' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'screenrecorder': True } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screenrecorder": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screenrecorder"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | boolean | true | ### Test Privacy Make the test results for this test public so that everyone can access the results. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["public"] = false DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("public", false); $caps = array( "public" => false ); capabilities = { "public" : False } const capabilities = { "public" : false } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("public", false); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "public" : false } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("public", false); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'public' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'public': False } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "public": false } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["public"] = false }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | boolean | false | ### Blacklist hostnames The hostnames you specify will be pointed to localhost instead of their real destination. This means you can speed up tests by blocking third party content which you don't need and slows down your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["blacklist"] = "site1.com,site2.com" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("blacklist", "site1.com,site2.com"); $caps = array( "blacklist" => "site1.com,site2.com" ); capabilities = { "blacklist" : "site1.com,site2.com" } const capabilities = { "blacklist" : "site1.com,site2.com" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("blacklist", "site1.com,site2.com"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "blacklist" : "site1.com,site2.com" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("blacklist", "site1.com,site2.com"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'blacklist' => "site1.com,site2.com" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'blacklist': "site1.com,site2.com" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "blacklist": "site1.com,site2.com" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["blacklist"] = "site1.com,site2.com" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string (comma-separated) | ### Customize Logging By default, TestingBot records logs of all Selenium actions and its drivers. Set this option to `false` if you don't want TestingBot to record anything (for example, if you have sensitive data). You will not see any test logs in our member dashboard. Set to `strip-parameters` to prevent the POST/GET parameters from being logged on the TestingBot test detail page (does not affect other logs like Selenium logs, Chromedriver logs, ...). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["recordLogs"] = true DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("recordLogs", true); $caps = array( "recordLogs" => true ); capabilities = { "recordLogs" : True } const capabilities = { "recordLogs" : true } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("recordLogs", true); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "recordLogs" : true } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("recordLogs", true); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'recordLogs' => true )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'recordLogs': True } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "recordLogs": true } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["recordLogs"] = true }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | "true" | `true`, `false`, or `strip-parameters` | ### Custom Time Zones Change the Time Zone of the Virtual Machine to the Time Zone you specify. You can find a [list of timezones on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Only location names are supported (not their paths). See some examples below: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["timeZone"] = "Etc/UTC" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("timeZone", "Etc/UTC"); $caps = array( "timeZone" => "Etc/UTC" ); capabilities = { "timeZone" : "Etc/UTC" } const capabilities = { "timeZone" : "Etc/UTC" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("timeZone", "Etc/UTC"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "timeZone" : "Etc/UTC" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("timeZone", "Etc/UTC"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'timeZone' => "Etc/UTC" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'timeZone': "Etc/UTC" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "timeZone": "Etc/UTC" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["timeZone"] = "Etc/UTC" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | Possible Values: | | --- | --- | --- | | string | "Etc/UTC" | [List of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | ### Change Screen Resolution Will adjust the screen resolution during your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screen-resolution"] = "1280x1024" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screen-resolution", "1280x1024"); $caps = array( "screen-resolution" => "1280x1024" ); capabilities = { "screen-resolution" : "1280x1024" } const capabilities = { "screen-resolution" : "1280x1024" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screen-resolution", "1280x1024"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "screen-resolution" : "1280x1024" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("screen-resolution", "1280x1024"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'screen-resolution' => "1280x1024" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'screen-resolution': "My Test Name" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "screen-resolution": "1280x1024" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["screen-resolution"] = "1280x1024" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | | --- | --- | --- | | string | "1280x1024" | | Platform | Resolutions | | --- | --- | | Windows/Linux | 800x600 1024x768 1152x864 1280x768 1280x800 1280x960 1280x1024 1400x1050 1600x1200 1680x1050 1920x1080 1920x1200 2560x1440 | | macOS | 800x600 1024x768 1280x768 1280x800 1280x960 1280x1024 1366x768 1440x900 1600x900 1600x1200 1680x1050 1920x1080 1920x1200 2048x1536 | | ### Customize OS When you specify a prerun file, we will first download the file and execute it (with optional prerun-arguments). This is useful when you want to customize/add software before your test starts. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["prerun"] = "https://..." DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("prerun", "https://..."); $caps = array( "prerun" => "https://..." ); capabilities = { "prerun" : "https://..." } const capabilities = { "prerun" : "https://..." } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("prerun", "https://..."); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "prerun" : "https://..." } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("prerun", "https://..."); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'prerun' => "https://..." )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'prerun': "https://..." } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "prerun": "https://..." } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["prerun"] = "https://..." }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string (URL) | "prerun-args" : "-a -b -c ..." | Value Type | | --- | | string | With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your executable on our servers. The advantage of this is that our test VMs can immediately download your executable from our own network, which is much faster than downloading from the public internet. Once the file is uploaded via TestingBot Storage, you can use `"prerun" : "tb://..."` ### Edit hostnames You can specify an array of objects containing the keys `ip` and `domain`. We will write these values to the hosts file of the VM. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["hosts"] = [{ ip: '127.0.0.1', domain: 'mydomain' }] DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("hosts", [{ ip: '127.0.0.1', domain: 'mydomain' }]); $caps = array( "hosts" => [{ ip: '127.0.0.1', domain: 'mydomain' }] ); capabilities = { "hosts" : [{ ip: '127.0.0.1', domain: 'mydomain' }] } const capabilities = { "hosts" : [{ ip: '127.0.0.1', domain: 'mydomain' }] } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("hosts", [{ ip: '127.0.0.1', domain: 'mydomain' }]); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "hosts" : [{ ip: '127.0.0.1', domain: 'mydomain' }] } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("hosts", [{ ip: '127.0.0.1', domain: 'mydomain' }]); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'hosts' => [{ ip: '127.0.0.1', domain: 'mydomain' }] )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'hosts': [{ ip: '127.0.0.1', domain: 'mydomain' }] } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "hosts": [{ ip: '127.0.0.1', domain: 'mydomain' }] } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["hosts"] = [{ ip: '127.0.0.1', domain: 'mydomain' }] }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | array of objects `({ ip: "", domain: "" })` | ### Upload file When you specify an URL (`upload`) and fileName (`uploadFilepath`), we will automatically download the file from the URL and save it in the uploadFilepath. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["upload"] = "https://..." DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("upload", "https://..."); $caps = array( "upload" => "https://..." ); capabilities = { "upload" : "https://..." } const capabilities = { "upload" : "https://..." } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("upload", "https://..."); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "upload" : "https://..." } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("upload", "https://..."); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'upload' => "https://..." )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'upload': "https://..." } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "upload": "https://..." } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["upload"] = "https://..." }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string (URL) | We recommend using these directories to save your files: For Windows (`C:\test\`), for Linux/macOS: (`/tmp/`). You can also use the home directory tilde to specify the user's directory: `~/Desktop/sample.pdf` Example: "uploadFilepath" : "C:\\test\\myfile.ext" Example (Selenium 4): "tb:options" : { "uploadFilepath" : "C:\\test\\myfile.ext" } | Value Type | | --- | | string (URL) | ### Upload Multiple Files Specify an array of objects, containing keys `url` and `filePath`. We will automatically download these files and put them in the filePaths you specify. We recommend using these directories to save your files: For Windows (`C:\test\`), for Linux/macOS: (`/tmp/`). You can also use the home directory tilde to specify the user's directory: `~/Desktop/sample.pdf` [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["uploadMultiple"] = [{ url: "", filePath: "" }] DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("uploadMultiple", [{ url: "", filePath: "" }]); $caps = array( "uploadMultiple" => [{ url: "", filePath: "" }] ); capabilities = { "uploadMultiple" : [{ url: "", filePath: "" }] } const capabilities = { "uploadMultiple" : [{ url: "", filePath: "" }] } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("uploadMultiple", [{ url: "", filePath: "" }]); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "uploadMultiple" : [{ url: "", filePath: "" }] } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("uploadMultiple", [{ url: "", filePath: "" }]); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'uploadMultiple' => [{ url: "", filePath: "" }] )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'uploadMultiple': [{ url: "", filePath: "" }] } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "uploadMultiple": [{ url: "", filePath: "" }] } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["uploadMultiple"] = [{ url: "", filePath: "" }] }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | array of objects, `{ url: "", filePath: "" }` | ### Geolocation Testing We provide an option where you can specify from which country you'd like to run the test from. Once you specify this option, the virtual machine we provision for your test will be configured to use a proxy in the country you specified. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["testingbot.geoCountryCode"] = "DE" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("testingbot.geoCountryCode", "DE"); $caps = array( "testingbot.geoCountryCode" => "DE" ); capabilities = { "testingbot.geoCountryCode" : "DE" } const capabilities = { "testingbot.geoCountryCode" : "DE" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("testingbot.geoCountryCode", "DE"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "testingbot.geoCountryCode" : "DE" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("testingbot.geoCountryCode", "DE"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'testingbot.geoCountryCode' => "DE" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'testingbot.geoCountryCode': "DE" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "testingbot.geoCountryCode": "DE" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["testingbot.geoCountryCode"] = "DE" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); Specify `testingbot.geoCountryCode` with one of the following country codes: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States **Important:** this does not work on Android 4.4 ### Localhost Testing By default, the TestingBot remote VMs are not able to access your localhost, as they are running in a separate network. However, you can use the `localhost` address to access your local web server when using the [TestingBot Tunnel](https://testingbot.com/support/tunnel). Once you have the TestingBot Tunnel running, these localhost ports will be forwarded to your machine: - 80 - 443 - 8080 - 3030 - 3000 - 3001 - 3400 You can also specify additional ports to forward by using the `localHttpPorts` capability. If the localhost port is expecting SSL traffic, you can specify the port in the `localHttpsPorts` capability. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) caps = { "tb:options" => { "localHttpPorts" : [3002, 8081] } } MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("localHttpPorts", [3002, 8081]); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("tb:options", tbOptions); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability('tb:options', array( "localHttpPorts" => [3002, 8081] )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'localHttpPorts': [3002, 8081] } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "tb:options": { "localHttpPorts": [3002, 8081] } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["testingbot.localHttpPorts"] = [3002, 8081] }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### Change Test Name Add a name to this test, which will show up in our member area and API. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["name"] = "My Test Name" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("name", "My Test Name"); $caps = array( "name" => "My Test Name" ); capabilities = { "name" : "My Test Name" } const capabilities = { "name" : "My Test Name" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("name", "My Test Name"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "name" : "My Test Name" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("name", "My Test Name"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'name' => "My Test Name" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': "My Test Name" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "name": "My Test Name" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = "My Test Name" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | string | unnamed test | ### Group Tests A key you can use to group certain tests in the same build (for example in Jenkins). The builds will appear in our member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["build"] = "My First Build" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("build", "My First Build"); $caps = array( "build" => "My First Build" ); capabilities = { "build" : "My First Build" } const capabilities = { "build" : "My First Build" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("build", "My First Build"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "build" : "My First Build" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("build", "My First Build"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'build' => "My First Build" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'build': "My First Build" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "build": "My First Build" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["build"] = "My First Build" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string | ### Idle Timeout The maximum amount of time a browser will wait before proceeding to the next step in your test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["idletimeout"] = 130 DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("idletimeout", 130); $caps = array( "idletimeout" => 130 ); capabilities = { "idletimeout" : 130 } const capabilities = { "idletimeout" : 130 } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("idletimeout", 130); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "idletimeout" : 130 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("idletimeout", 130); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'idletimeout' => 130 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'idletimeout': 130 } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "idletimeout": 130 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["idletimeout"] = 130 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | int (specify number of seconds) | 130 seconds | ### Maximum Test Duration The maximum duration for a single test. This is a safeguard to prevent bad tests from using up your credits. We generally recommend to keep tests short (less than 10 minutes). It's better to split up large tests in smaller individual tests. This keeps your tests fast and allows for more parallelization of your tests. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["maxduration"] = 1800 DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("maxduration", 1800); $caps = array( "maxduration" => 1800 ); capabilities = { "maxduration" : 1800 } const capabilities = { "maxduration" : 1800 } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("maxduration", 1800); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "maxduration" : 1800 } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("maxduration", 1800); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'maxduration' => 1800 )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'maxduration': 1800 } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "maxduration": 1800 } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["maxduration"] = 1800 }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Default Value | | --- | --- | | int (specify number of seconds) | 1800 seconds (30 minutes) | ### Custom Metadata Send along custom data, for example your release, server, commit hash, ... This will show up on the test detail page in the TestingBot member area. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["extra"] = "Extra Information" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("extra", "Extra Information"); $caps = array( "extra" => "Extra Information" ); capabilities = { "extra" : "Extra Information" } const capabilities = { "extra" : "Extra Information" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("extra", "Extra Information"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "extra" : "Extra Information" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("extra", "Extra Information"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'extra' => "Extra Information" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'extra': "Extra Information" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "extra": "Extra Information" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["extra"] = "Extra Information" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string | ### Load custom browser extensions If you specify this desired capability with the URL to your Chrome extension's `.crx` file, Safari App/Web extension file, or Firefox addon's `.xpi` file, we will download the extension, which will be added to the browser before your test starts. More information is available in the [automated browser extension testing documentation](https://testingbot.com/support/web-automate/selenium/browser-extension). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["load-extension"] = "https://..." DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("load-extension", "https://..."); $caps = array( "load-extension" => "https://..." ); capabilities = { "load-extension" : "https://..." } const capabilities = { "load-extension" : "https://..." } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("load-extension", "https://..."); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "load-extension" : "https://..." } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("load-extension", "https://..."); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'load-extension' => "https://..." )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'load-extension': "https://..." } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "load-extension": "https://..." } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["load-extension"] = "https://..." }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Browser | Supported Format | Example | | --- | --- | --- | | Chrome | `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) | `https://.../extension.zip` | | Firefox | `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, `lib/ directory`, ...) | `https://.../extension.zip` | | Edge | `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) | `https://.../extension.zip` | | Safari (and Safari Technology Preview) | `Safari Web Extension, Safari App Extension or .safariextz` file | `https://.../extension.zip or https://.../extension.safariextz` | With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your executable on our servers. The advantage of this is that our test VMs can immediately download your executable from our own network, which is much faster than downloading from the public internet. Once the file is uploaded via TestingBot Storage, you can use `"prerun" : "tb://..."` ### Grouping Specify in which groups you want to see the test results. You can group results to have an easy overview of tests across projects. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["groups"] = "group1,group2" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("groups", "group1,group2"); $caps = array( "groups" => "group1,group2" ); capabilities = { "groups" : "group1,group2" } const capabilities = { "groups" : "group1,group2" } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("groups", "group1,group2"); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "groups" : "group1,group2" } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("groups", "group1,group2"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'groups' => "group1,group2" )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'groups': "group1,group2" } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "groups": "group1,group2" } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["groups"] = "group1,group2" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string (comma-separated) | ### AutoClicker Specify one or more of the possible options below to have TestingBot automatically click certain dialogs which are unable to be automated via Selenium WebDriver. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["autoclick"] = [] DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("autoclick", []); $caps = array( "autoclick" => [] ); capabilities = { "autoclick" : [] } const capabilities = { "autoclick" : [] } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("autoclick", []); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "autoclick" : [] } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("autoclick", []); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'autoclick' => [] )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'autoclick': [] } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "autoclick": [] } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["autoclick"] = [] }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | Possible Values: | | --- | --- | | array of options | `chrome_extension_add`, `chrome_extension_permissions_allow` | ### Sikuli Specify an URL to a zip-file containing one or more `.sikulu` projects. These will automatically start before your test runs, so that you can do certain automated tasks which Selenium cannot do (clicking native dialogs, ...) Find more information regarding [Sikuli Cloud Testing](https://testingbot.com/support/other/sikuli). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["sikuli"] = "https://..." DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("sikuli", "https://..."); $caps = array( "sikuli" => "https://..." ); capabilities = { "sikuli" : "https://..." } const capabilities = { "sikuli" : "https://..." } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("sikuli", "https://..."); **Selenium W3C Example:** [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "sikuli" : [] } } ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("sikuli", []); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'sikuli' => [] )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'sikuli': [] } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', /** Google requires "w3c" to be set in "goog:chromeOptions" as true if you're using ChromeDriver version 74 or lower. * Based on this commit: https://chromium.googlesource.com/chromium/src/+/2b49880e2481658e0702fd6fe494859bca52b39c * ChromeDriver now uses w3c by default from version 75+ so setting this option will no longer be a requirement **/ "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "sikuli": [] } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "81", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["sikuli"] = [] }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); | Value Type | | --- | | string (URL to zipped Sikuli project) | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/network ### Available Commands: - [Throttle Network](https://testingbot.com#throttle) - [Intercept/Mock Network](https://testingbot.com#intercept) - [Network Log](https://testingbot.com#network) # Custom WebDriver Commands by TestingBot TestingBot has added custom WebDriver commands for Chrome and Microsoft Edge browsers. With these custom commands, you can **retrieve various metrics** , **throttle network speed** and **monitor/adjust network requests** during your test. These custom commands can be used with WebDriver's `JavascriptExecutor`. **Important:** to be able to use these commands, **you need to pass** `debugging: true` in your desired capabilities. ## Throttle Network #### Description: This call allows you to throttle network speed, or even simulate no network connection (offline-mode). [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script("tb:throttle", "3G") # or driver.execute_script("tb:throttle", { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }) ((JavascriptExecutor) driver).executeScript("tb:throttle", "3G"); // or Map throttleMap = new HashMap<>(); throttleMap.put("downloadSpeed", 10 * 1024); throttleMap.put("uploadSpeed", 10 * 1024); throttleMap.put("latency", 0); throttleMap.put("loss", 0); ((JavascriptExecutor) driver).executeScript("tb:throttle", throttleMap); $driver->executeScript("tb:throttle", ["3G"]); // or $driver->executeScript("tb:throttle", [ "downloadSpeed" => 10 * 1024, "uploadSpeed" => 10 * 1024, "latency" => 0, "loss" => 0 ]); driver.execute_script("tb:throttle", "3G") # or driver.execute_script("tb:throttle", { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }) await driver.executeScript('tb:throttle', '3G'); // or await driver.executeScript('tb:throttle', { "downloadSpeed": 10 * 1024, "uploadSpeed": 10 * 1024, "latency": 0, "loss": 0 }); ((IJavaScriptExecutor)driver).ExecuteScript("tb:throttle", "3G"); // or ((IJavaScriptExecutor)driver).ExecuteScript("tb:throttle", "{\"downloadSpeed\":10240, \"uploadSpeed\": 10240, \"latency\": 0, \"loss\": 0}"); #### Options: | `tb:throttle` Specifying a predefined condition | Condition | Download Speed (kb/sec) | Upload Speed (kb/sec) | Latency (ms) || `airplane` Simulate Offline Mode | 0 | 0 | 0 | | `disable` Default - useful if you want to undo the `offline` command. | no throttle | no throttle | no throttle | | `edge` | 250 | 150 | 300 | | `3G` | 400 | 100 | 100 | | `4G` | 18000 | 9000 | 100 | | | `tb:throttle` Specify custom settings | `downloadSpeed` | `uploadSpeed` | `latency` || ... kb / sec | ... kb / sec | ... ms | | ## Intercept/Mock #### Description: With these commands, you can intercept and even fake responses during your test. Blacklist requests, add/modify headers, mock responses, ... The `url` parameter supports wildcard statements, for example: `https://www.testingbot.com/*`. ### Redirect a URL Instructs Chrome/Edge to redirect to `redirect` upon navigating to `url`. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script("tb:intercept", { "redirect": "https://www.google.com", "url": "https://testingbot.com", }) Map interceptMap = new HashMap<>(); interceptMap.put("redirect", "https://www.google.com"); interceptMap.put("url", "https://testingbot.com"); ((JavascriptExecutor) driver).executeScript("tb:intercept", interceptMap); $driver->executeScript("tb:intercept", [ "redirect" => "https://google.com", "url" => "https://testingbot.com" ]); driver.execute_script("tb:intercept", { "redirect": "https://google.com", "url": "https://testingbot.com" }) await driver.executeScript('tb:intercept', { "redirect": "https://google.com", "url": "https://testingbot.com" }); ((IJavaScriptExecutor)driver).ExecuteScript("tb:intercept", "{\"redirect\":\"https://www.google.com\", \"url\": \"https://testingbot.com\"}"); ### Trigger Failure Allows you to return a specific error for a specific request. [Possible errors](https://chromedevtools.github.io/devtools-protocol/tot/Network#type-ErrorReason): - Failed - Aborted - TimedOut - AccessDenied - ConnectionClosed - ConnectionReset - ConnectionRefused - ConnectionAborted - ConnectionFailed - NameNotResolved - InternetDisconnected - AddressUnreachable - BlockedByClient - BlockedByResponse [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script("tb:intercept", { "error": "ConnectionRefused", "url": "https://testingbot.com" }) Map interceptMap = new HashMap<>(); interceptMap.put("error", "ConnectionRefused"); interceptMap.put("url", "https://testingbot.com"); ((JavascriptExecutor) driver).executeScript("tb:intercept", interceptMap); $driver->executeScript("tb:intercept", [ "error" => "ConnectionRefused", "url" => "https://testingbot.com" ]); driver.execute_script("tb:intercept", { "error": "ConnectionRefused", "url": "https://testingbot.com" }) await driver.executeScript('tb:intercept', { "error": "ConnectionRefused", "url": "https://testingbot.com" }); ((IJavaScriptExecutor)driver).ExecuteScript("tb:intercept", "{\"error\":\"ConnectionRefused\", \"url\": \"https://testingbot.com\"}"); ### Mock Response Allows you to return a different response (body or headers). [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script("tb:intercept", { "response": { "statusCode": 200, "headers": { "x-a-header": "Sample" }, "body": "Hello World" }, "url": "https://testingbot.com" }) Map mockMap = new HashMap<>(); Map headersMap = new HashMap<>(); headersMap.put("x-a-header", "Sample"); Map responseMap = new HashMap<>(); responseMap.put("statusCode", 200); responseMap.put("headers", headersMap); responseMap.put("body", "Hello World"); mockMap.put("response", responseMap); mockMap.put("url", "https://testingbot.com"); ((JavascriptExecutor) driver).executeScript("tb:intercept", mockMap); $driver->executeScript("tb:intercept", [ "response" => [ "statusCode" => 200, "headers" => [ "x-a-header" => "Sample" ], "body" => "Hello World" ], "url" => "https://testingbot.com" ]); driver.execute_script("tb:intercept", { "response": { "statusCode": 200, "headers": { "x-a-header": "Sample" }, "body": "Hello World" }, "url": "https://testingbot.com" }) await driver.executeScript('tb:intercept', { "response": { "statusCode": 200, "headers": { "x-a-header": "Sample" }, "body": "Hello World" }, "url": "https://testingbot.com" }); ((IJavaScriptExecutor)driver).ExecuteScript("tb:intercept", "{\"response\":{\"statusCode\": 200, \"headers\": { \"x-a-header\": \"Sample\"}, \"body\": \"Hello World\" }, \"url\": \"https://testingbot.com\"}"); ## Retrieve Network Log #### Description: With the `tb:network` command you can fetch a log of network calls from Chrome and Microsoft Edge. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script("tb:network") ((JavascriptExecutor) driver).executeScript("tb:network"); $driver->executeScript("tb:network"); driver.execute_script("tb:network") await driver.executeScript('tb:network'); ((IJavaScriptExecutor)driver).ExecuteScript("tb:network"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php ### PHP Examples: - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) # PHP Automated Testing Let's start with making sure PHP is available on your system. **For Windows:** - You can download PHP for Windows from [PHP For Windows](https://windows.php.net/download/). - Run the installer and follow the setup wizard to install PHP. **For Linux:** sudo apt-get install curl libcurl3 libcurl3-dev php **For macOS:** PHP should already be present on macOS by default. [![Video tutorial on How to run PHP Automated Test on TestingBot](https://testingbot.com/assets/videos/php-automated-4985ae1c28644d70de6288090302df66c8c7c02227aed461ca24c0659572f688.webp)](https://testingbot.com#) about:blank See our [PHP example repository](https://github.com/testingbot/php-phpunit-example) for a first example on how to run PHP tests in parallel on TestingBot. ## Installation With TestingBot you can easily run your automated tests with [any PHP test framework](https://testingbot.com#frameworks), here's a first example with **php-webdriver** : php composer.phar require php-webdriver/webdriver Save the example code below in a file called `sampletest.php` "WINDOWS", "browserName"=>"chrome", "version" => "latest", "name" => "First Test"), 120000 ); $web_driver->get("https://google.com"); $element = $web_driver->findElement(WebDriverBy::name("q")); if($element) { $element->sendKeys("TestingBot"); $element->submit(); } print $web_driver->getTitle(); $web_driver->quit(); ?> You can now run this test: php sampletest.php ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** $web_driver = RemoteWebDriver::create("http://localhost:4444/wd/hub", array("platform"=>"WINDOWS", "browserName"=>"chrome"), 120000); **After:** $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", array("platform"=>"WINDOWS", "browserName"=>"chrome"), 120000); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. $web_driver = RemoteWebDriver::create( "http://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PHP WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: "WINDOWS", "browserName"=>"firefox", "version" => "latest", "name" => "First Test"), 120000 ); $web_driver->get("https://google.com"); $element = $web_driver->findElement(WebDriverBy::name("q")); if($element) { $element->sendKeys("TestingBot"); $element->submit(); } print $web_driver->getTitle(); $web_driver->quit(); ?> ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using [Paratest](https://github.com/brianium/paratest), which makes it very easy to run multiple PHPUnit tests simultaneously. vendor/bin/paratest -p 8 -f --phpunit=vendor/bin/phpunit WebdriverTest.php The command above will run your tests in 8 separate processes (8 tests at once). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [PHP API client](https://github.com/testingbot/testingbot-php) to report back test results. $api = new TestingBot\TestingBotAPI($apiKey, $apiSecret); $api->updateJob($web_driver->getSessionID(), array('name' => 'mytest', 'success' => true)); ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) Laravel Dusk provides an easy-to-use browser automation testing framework. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php/behat-mink # Behat Automated Testing See our [Behat 2 example](https://github.com/testingbot/behat-selenium-sample) or [Behat 3 example](https://github.com/testingbot/behat-selenium-sample/tree/behat3) for some simple examples on how to run Behat tests on TestingBot. TestingBot supports Selenium tests using Behat. It's very easy to create or convert Behat tests to use our Selenium Grid. Behat is a Behavior-Driven Development framework for PHP. You can find more information on the [Behat Documentation Pages](https://docs.behat.org/en/latest/). ## Installation Make sure you have `Composer` installed: curl http://getcomposer.org/installer | php First make sure you've installed Behat. See this example with PHP Composer: php composer.phar install Next, let's create the necessary files: **composer.json** : { "require": { "behat/behat": "2.5.*@stable", "facebook/webdriver": "dev-master", "symfony/yaml": "*" }, "config": { "bin-dir": "bin/" }, "scripts": { "test": "composer single && composer parallel", "single": "./vendor/behat/behat/bin/behat --config=config/single.conf.yml", "parallel": "CONFIG_FILE=config/parallel.conf.yml /usr/bin/env php lib/parallel.php" }, "autoload": { "classmap": ["lib/"] } } Now we can create a simple testcase, written in Behat: **features/single/single.feature** Feature: Google Search Functionality Scenario: Can find search results Given I am on "https://www.google.com/ncr" When I search for "Google" Then I should see "Google" **lib/TestingBotContext.php** : $value) { if (!array_key_exists($key, $caps)) $caps[$key] = $value; } self::$driver = RemoteWebDriver::create($url, $caps); } /** @AfterFeature */ public static function tearDown() { self::$driver->quit(); } } ?> **features/bootstrap/FeatureContext.php** : get($url); } /** @When /^I search for "([^"]*)"$/ */ public function iSearchFor($searchText) { $element = self::$driver->findElement(WebDriverBy::name("q")); $element->sendKeys($searchText); $element->submit(); sleep(5); } /** @Then /^I get title as "([^"]*)"$/ */ public function iShouldGet($string) { $title = self::$driver->getTitle(); if ((string) $string !== $title) { throw new Exception("Expected title: '". $string. "'' Actual is: '". $title. "'"); } } /** @Then /^I should see "([^"]*)"$/ */ public function iShouldSee($string) { $source = self::$driver->getPageSource(); if (strpos($source, $string) === false) { throw new Exception("Expected to see: '". $string. "'' Actual is: '". $source. "'"); } } } To actually run this test, we first need to add some TestingBot settings to `config/single.conf.yml` default: paths: features: '../features/single' bootstrap: '../features/bootstrap' context: parameters: testingbot: server: "hub.testingbot.com" user: "key" key: "secret" capabilities: build: "behat-selenium-sample" name: "single-behat-test" environments: - browserName: chrome version: latest platform: Win10 You can now run this test on TestingBot using the following command: php composer.phar single ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PHP WebDriver test with our Tunnel: 1. [Download TestingBot Tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: default: paths: features: '../features/single' bootstrap: '../features/bootstrap' context: parameters: testingbot: server: "localhost:4445" user: "key" key: "secret" ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) Laravel Dusk provides an easy-to-use browser automation testing framework. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php/codeception # Codeception Automated Testing See our [CodeCeption example repository](https://github.com/testingbot/php-codeception-example) for a simple example on how to run CodeCeption tests in parallel on TestingBot. We start with a simple test: php codecept.phar generate:cept acceptance Welcome Make sure you set these values in `tests/acceptance.suite.yml` class_name: AcceptanceTester env: chrome: modules: enabled: - WebDriver config: WebDriver: url: 'https://www.google.com' host: 'hub.testingbot.com' port: 80 browser: chrome capabilities: 'client_key': 'REPLACE_ME' 'client_secret': 'REPLACE_ME' 'platform' : 'Windows' 'name': 'Sample Codeception Tests' firefox: modules: enabled: - WebDriver config: WebDriver: url: 'https://www.google.com' host: 'hub.testingbot.com' port: 80 browser: firefox capabilities: 'client_key': 'REPLACE_ME' 'client_secret': 'REPLACE_ME' 'platform': LINUX 'name': 'Sample Codeception Tests' Now we can run a basic example where we search for TestingBot on Google: wantTo('Search TestingBot on Google'); $I->amOnPage('/'); $I->see('Google'); $I->fillField('q', 'TestingBot'); $I->click('btnG'); $I->see('TestingBot'); ?> Additional settings can be found on the [Codeception WebDriver Module page](https://codeception.com/docs/modules/WebDriver). ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. We've created an extension for Codeception: [testingbot/codeception-extension](https://github.com/testingbot/codeception-extension) By including this in your tests, Codeception will automatically send back test-meta data to TestingBot (test name, success/failure, ...) ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution.") %\> The example below shows how to easily run a Codeception test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back. Edit the configuration in `tests/acceptance.suite.yml`: class_name: AcceptanceTester env: chrome: modules: enabled: - WebDriver config: WebDriver: url: 'https://www.google.com' host: 'localhost' port: 4445 browser: chrome capabilities: 'client_key': 'REPLACE_ME' 'client_secret': 'REPLACE_ME' 'platform' : 'Windows' 'name': 'Sample Codeception Tests' ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Please see [CodeCeption Parallel Execution Docs](https://codeception.com/docs/ParallelExecution) for more information on how to run tests in parallel with [Robo-paracept](https://github.com/Codeception/robo-paracept). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) Laravel Dusk provides an easy-to-use browser automation testing framework. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php/laravel-dusk # Laravel Automated Testing Let's start with making sure PHP is available on your system. **For Windows:** - You can download PHP for Windows from [PHP For Windows](https://windows.php.net/download/). - Run the installer and follow the setup wizard to install PHP. **For Linux:** sudo apt-get install curl libcurl3 libcurl3-dev php **For macOS:** brew install php ## Installation - Make sure you have [Composer installed](https://getcomposer.org/). - Install the [Laravel Dusk Framework](https://laravel.com/docs/master/dusk) and other dependencies creating this `composer.json` file: - Install the dependencies by running: - Install the necessary Dusk files: ## Configuration If you followed the steps above, you should now have a `tests/DuskTestCase.php` file. You can now generate a sample test file, for example with: php artisan dusk:make LoginTest To connect your test with TestingBot, you'll need to edit the `tests/DuskTestCase.php` file with the following contents: protected function driver() { $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('tb:options', [ 'key' => env('TESTINGBOT_KEY'), 'secret' => env('TESTINGBOT_SECRET'), 'name' => $this->getName() ]); return RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities, 120000 ); } To run the test, please enter this command: php artisan dusk ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** $capabilities = DesiredCapabilities::chrome(); $web_driver = RemoteWebDriver::create( 'http://localhost:4444/wd/hub', $capabilities ); **After:** $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('tb:options', [ 'key' => env('TESTINGBOT_KEY'), 'secret' => env('TESTINGBOT_SECRET') ]); $web_driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities ); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. $capabilities->setCapability('tb:options', [ 'key' => env('TESTINGBOT_KEY'), 'secret' => env('TESTINGBOT_SECRET') ]); $web_driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities ); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Laravel Dusk test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: protected function driver() { $capabilities = DesiredCapabilities::firefox(); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('tb:options', [ 'key' => env('TESTINGBOT_KEY'), 'secret' => env('TESTINGBOT_SECRET') ]); return RemoteWebDriver::create( 'http://localhost:4445/wd/hub', $capabilities, 120000 ); } ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php/phpunit # PHPUnit Automated Testing See our [PHPUnit example repository](https://github.com/testingbot/php-phpunit-example) for a simple example on how to run PHPUnit tests in parallel on TestingBot. Let's start with making sure PHP is available on your system. **For Windows:** - You can download PHP for Windows from [PHP For Windows](https://windows.php.net/download/). - Run the installer and follow the setup wizard to install PHP. **For Linux:** sudo apt-get install curl libcurl3 libcurl3-dev php **For macOS:** PHP should already be present on macOS by default. ## Installation - Make sure you have [Composer installed](https://getcomposer.org/). - Install PHPUnit by running this command in your terminal: ## PHPUnit Example Require the PHP-WebDriver client like this: php composer.phar require facebook/webdriver Now, you can paste this example code in file called `WebDriverTest.php` _session = RemoteWebDriver::create("https://api_key:api_secret@hub.testingbot.com/wd/hub", array('platform' => "WINDOWS", "version" => 'latest', 'browserName' => 'chrome'), 120000 ); } public function tearDown() { $this->sendTestStatusToTestingBot(); $this->_session->quit(); unset($this->_session); parent::tearDown(); } public function testTitle() { $this->_session->get('https://www.google.com/'); $this->assertEquals('Google', $this->_session->getTitle()); } protected function sendTestStatusToTestingBot() { $sessionID = $this->_session->getSessionID(); $postData = array( 'session_id' => $sessionID, 'client_key' => "api_key", 'client_secret' => "api_secret", 'test[status_message]' => $this->getStatusMessage(), 'test[success]' => !$this->hasFailed(), 'test[name]' => $this->toString() ); $data = http_build_query($postData); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://api.testingbot.com/v1/tests/" . $postData['session_id']); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_USERPWD, $postData['client_key'] . ":" . $postData['client_secret']); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); $response = curl_exec($curl); curl_close($curl); } } To run the test, please enter this command: ./vendor/bin/phpunit WebDriverTest.php ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** $web_driver = RemoteWebDriver::create("http://localhost:4444/wd/hub", array("platform"=>"WINDOWS", "browserName"=>"chrome"), 120000); **After:** $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", array("platform"=>"WINDOWS", "browserName"=>"chrome"), 120000); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. $web_driver = RemoteWebDriver::create( "http://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PHP WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: _session = RemoteWebDriver::create("http://api_key:api_secret@localhost:4445/wd/hub", array('platform' => "WINDOWS", "version" => 'latest', 'browserName' => 'firefox'), 120000 ); } public function testTitle() { $this->_session->get('https://www.google.com/'); $this->assertEquals('Google', $this->_session->title()); } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using [Paratest](https://github.com/brianium/paratest), which makes it very easy to run multiple PHPUnit tests simultaneously. vendor/bin/paratest -p 8 -f --phpunit=vendor/bin/phpunit WebdriverTest.php The command above will run your tests in 8 separate processes (8 tests at once). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [PHP API client](https://github.com/testingbot/testingbot-php) to report back test results. $api = new TestingBot\TestingBotAPI($apiKey, $apiSecret); $api->updateJob($web_driver->getSessionID(), array('name' => 'mytest', 'success' => true)); ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) Laravel Dusk provides an easy-to-use browser automation testing framework. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/php/simpletest # SimpleTest Automated Testing You can find more information about SimpleTest on the [SimpleTest Repo](https://github.com/simpletest/simpletest). To use the example below, you'll need to download [php-webdriver](https://github.com/php-webdriver/php-webdriver) as well. "WINDOWS", "browserName" => "chrome", "version" => "latest"), 120000 ); $web_driver->get("https://www.google.com"); $this->assertEquals("Google", $web_driver->getTitle()); $element = $web_driver->findElement(WebDriverBy::name("q")); if ($element) { $element->sendKeys("TestingBot"); $element->submit(); } $web_driver->quit(); } function assertEquals($text, $value) { if ($text === $value) return true; else return false; } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. $web_driver = RemoteWebDriver::create( "http://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a SimpleTest WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: "WINDOWS", "browserName" => "chrome", "version" => "latest"), 120000 ); $web_driver->get("https://www.google.com"); $this->assertEquals("Google", $web_driver->getTitle()); $element = $web_driver->findElement(WebDriverBy::name("q")); if ($element) { $element->sendKeys("TestingBot"); $element->submit(); } $web_driver->quit(); } function assertEquals($text, $value) { if ($text === $value) return true; return false; } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using [Paratest](https://github.com/brianium/paratest), which makes it very easy to run multiple PHPUnit tests simultaneously. vendor/bin/paratest -p 8 -f --phpunit=vendor/bin/phpunit WebdriverTest.php The command above will run your tests in 8 separate processes (8 tests at once). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [PHP API client](https://github.com/testingbot/testingbot-php) to report back test results. $api = new TestingBot\TestingBotAPI($apiKey, $apiSecret); $api->updateJob($web_driver->getSessionID(), array('name' => 'mytest', 'success' => true)); ## Other PHP Framework examples - [Behat](https://testingbot.com/support/web-automate/selenium/php/behat-mink) Behat is a BDD framework which runs on PHP. Mink is used for its browser emulation and works nicely together with Behat. - [Codeception](https://testingbot.com/support/web-automate/selenium/php/codeception) Codeception is a BDD-styled PHP testing framework. This testing framework offers good Selenium support. - [Laravel Dusk](https://testingbot.com/support/web-automate/selenium/php/laravel-dusk) Laravel Dusk provides an easy-to-use browser automation testing framework. - [PHPUnit](https://testingbot.com/support/web-automate/selenium/php/phpunit) PHPUnit is the most popular unit testing framework for PHP. It comes with good Selenium WebDriver support and is easy to set up. - [SimpleTest](https://testingbot.com/support/web-automate/selenium/php/simpletest) SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java ### Java Examples: - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) - [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide) - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) # Java Automated Testing Let's start with making sure Java is available on your system. We recommend Java 11 or newer (LTS versions like 11, 17 or 21). **For Windows:** - Download Java from [Eclipse Adoptium](https://adoptium.net/) or [Oracle](https://www.oracle.com/java/technologies/downloads/). - Run the installer and follow the setup wizard. - Verify the installation: `java -version` **For Linux (Debian/Ubuntu):** sudo apt-get install openjdk-17-jdk **For macOS:** brew install openjdk@17 Alternatively, download from [Eclipse Adoptium](https://adoptium.net/). ## Example With TestingBot you can easily run your automated tests with [any Java test framework](https://testingbot.com#frameworks). Here's a simple example to get started: ### Dependencies Add the Selenium dependency to your project: **Maven (pom.xml):** org.seleniumhq.selenium selenium-java 4.39.0 **Gradle (build.gradle):** implementation 'org.seleniumhq.selenium:selenium-java:4.39.0' Alternatively, you can [download the JAR files](https://www.selenium.dev/downloads/) `(selenium-java-*.zip)` manually. ### Basic Test import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class JavaSample { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { ChromeOptions options = new ChromeOptions(); Map tbOptions = new HashMap<>(); tbOptions.put("name", "My First Test"); tbOptions.put("platform", "WIN10"); options.setCapability("tb:options", tbOptions); WebDriver driver = null; try { driver = new RemoteWebDriver(new URL(URL), options); driver.get("https://testingbot.com"); System.out.println("Page title is: " + driver.getTitle()); } finally { if (driver != null) { driver.quit(); } } } } This test will start a remote Chrome browser on Windows 10, open the TestingBot website and print the title of the page. This test does not make any assertions or verifications, but it's a quick intro in how to run a Java test on TestingBot. Make sure to always stop your test (`driver.quit()`), otherwise it will continue running, leading to a timeout. ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** WebDriver driver = new FirefoxDriver(); **After:** FirefoxOptions options = new FirefoxOptions(); WebDriver driver = new RemoteWebDriver( new URL("https://key:secret@hub.testingbot.com/wd/hub"), options ); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Java test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class JavaSample { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String URL = "http://" + KEY + ":" + SECRET + "@localhost:4445/wd/hub"; public static void main(String[] args) throws Exception { ChromeOptions options = new ChromeOptions(); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Tunnel Test"); tbOptions.put("platform", "WIN10"); options.setCapability("tb:options", tbOptions); WebDriver driver = null; try { driver = new RemoteWebDriver(new URL(URL), options); driver.get("http://localhost:3000"); // Your internal website System.out.println("Page title is: " + driver.getTitle()); } finally { if (driver != null) { driver.quit(); } } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Please see our [Parallel JUnit documentation](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) for parallel testing. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark Tests as Passed or Failed To mark your test as passed or failed, or to send additional metadata to TestingBot, you can use our [API](https://testingbot.com/support/api). We provide a [Java client library](https://github.com/testingbot/testingbot-java) to help you interact with the TestingBot API easily. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once integrated into your test suite, you can programmatically update the test status and send metadata such as test name, build ID, or tags to TestingBot. import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @After public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. - [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide) Selenide is a Java-based test framework that provides a simple and concise API for writing Selenium tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java/junit # Set up your first Java test with JUnit See our [JUnit example repository](https://github.com/testingbot/java-junit-example) for a simple example on how to run JUnit tests in parallel on TestingBot. Below is a JUnit test example, showing you how to run a JUnit test on TestingBot import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.time.Duration; import java.util.HashMap; import java.util.Map; public class SimpleTest { private WebDriver driver; @Before public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); Map tbOptions = new HashMap<>(); tbOptions.put("name", "My JUnit Test"); tbOptions.put("platform", "WIN10"); options.setCapability("tb:options", tbOptions); String key = System.getenv("TB_KEY"); String secret = System.getenv("TB_SECRET"); driver = new RemoteWebDriver( new URL("https://" + key + ":" + secret + "@hub.testingbot.com/wd/hub"), options ); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); } @Test public void testSimple() throws Exception { driver.get("https://www.google.com"); assertEquals("Google", driver.getTitle()); } @After public void tearDown() throws Exception { if (driver != null) { driver.quit(); } } } ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** WebDriver driver = new FirefoxDriver(); **After:** FirefoxOptions options = new FirefoxOptions(); WebDriver driver = new RemoteWebDriver( new URL("https://key:secret@hub.testingbot.com/wd/hub"), options ); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a JUnit test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.time.Duration; import java.util.HashMap; import java.util.Map; public class SimpleTest { private WebDriver driver; @Before public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Tunnel Test"); tbOptions.put("platform", "WIN10"); options.setCapability("tb:options", tbOptions); String key = System.getenv("TB_KEY"); String secret = System.getenv("TB_SECRET"); driver = new RemoteWebDriver( new URL("http://" + key + ":" + secret + "@localhost:4445/wd/hub"), options ); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30)); } @Test public void testSimple() throws Exception { driver.get("http://localhost:3000"); // Your internal website assertEquals("My App", driver.getTitle()); } @After public void tearDown() throws Exception { if (driver != null) { driver.quit(); } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Please see our [Parallel JUnit documentation](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) for parallel testing. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To mark your test as passed or failed, or to send additional metadata to TestingBot, you can use our [API](https://testingbot.com/support/api). We provide a [Java client library](https://github.com/testingbot/testingbot-java) to help you interact with the TestingBot API easily. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once integrated into your test suite, you can programmatically update the test status and send metadata such as test name, build ID, or tags to TestingBot. import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @After public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. - [Selenide](https://testingbot.com/support/web-automate/selenium/java/selenide) Selenide is a Java-based test framework that provides a simple and concise API for writing Selenium tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java/parallel-junit # Speed up JUnit tests by running them in parallel By running multiple JUnit tests at the same time you can cut down on overall test time. ## Helper class needed to run JUnit tests in parallel import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.junit.runners.Parameterized; import org.junit.runners.model.RunnerScheduler; public class Parallelized extends Parameterized { private static class ThreadPoolScheduler implements RunnerScheduler { private ExecutorService executor; public ThreadPoolScheduler() { String threads = System.getProperty("junit.parallel.threads", "16"); int numThreads = Integer.parseInt(threads); executor = Executors.newFixedThreadPool(numThreads); } @Override public void finished() { executor.shutdown(); try { executor.awaitTermination(10, TimeUnit.MINUTES); } catch (InterruptedException exc) { throw new RuntimeException(exc); } } @Override public void schedule(Runnable childStatement) { executor.submit(childStatement); } } public Parallelized(Class klass) throws Throwable { super(klass); setScheduler(new ThreadPoolScheduler()); } } Below is a JUnit Test example, which uses the above helper class to run the test in parallel. import java.io.File; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; @RunWith(Parallelized.class) public class JUnitParallel { private String platform; private String browserName; private String browserVersion; @Parameterized.Parameters public static LinkedList getEnvironments() throws Exception { LinkedList env = new LinkedList<>(); env.add(new String[]{"WIN10", "chrome", "latest"}); env.add(new String[]{"WIN10", "firefox", "latest"}); env.add(new String[]{"WIN10", "MicrosoftEdge", "latest"}); // Add more browser configurations here return env; } public JUnitParallel(String platform, String browserName, String browserVersion) { this.platform = platform; this.browserName = browserName; this.browserVersion = browserVersion; } private WebDriver driver; @Before public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); options.setCapability("browserName", browserName); options.setCapability("browserVersion", browserVersion); options.setCapability("platformName", platform); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Parallel JUnit Test"); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URL("https://key:secret@hub.testingbot.com/wd/hub"), options ); } @Test public void testSimple() throws Exception { driver.get("https://www.google.com"); String title = driver.getTitle(); System.out.println("Page title is: " + title); File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); try { FileUtils.copyFile(srcFile, new File("Screenshot.png")); } catch (IOException e) { e.printStackTrace(); } } @After public void tearDown() throws Exception { driver.quit(); } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a JUnit test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: @Before public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); options.setCapability("browserName", browserName); options.setCapability("browserVersion", browserVersion); options.setCapability("platformName", platform); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Parallel Tunnel Test"); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URL("http://key:secret@localhost:4445/wd/hub"), options ); } ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you need to use our [API](https://testingbot.com/support/api). TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) for using the TestingBot API. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once included with your tests, you can send back test status and other meta-data to TestingBot: import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @After public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java/selenide # Selenide Automated Testing TestingBot has a [Selenide example GitHub project](https://github.com/testingbot/java-testng-selenide-example) available. This contains an example on how to run Selenide tests with TestingBot. Selenide is a Java-based test framework, capable of using Selenium WebDriver to test websites on (remote) browsers. You can use Selenide in combination with a test framework such as JUnit, TestNG, Cucumber and others. The syntax used by Selenide is short, it uses a concise API that makes your test code shorter and perhaps more readable. To get started, let's go over all the necessary steps required to run your first test with TestNG and Selenide, using TestingBot's remote browsers. ## Prerequisites Let's start with making sure Java is available on your system. Starting with Selenide 7, at least Java 17 is required. **For Windows:** - You can download Java for Windows from [Java.com](https://www.java.com/en/download/manual.jsp) - Run the installer and follow the setup wizard to install Java. **For Linux (Debian/Ubuntu):** sudo apt-get install openjdk-17-jdk **For macOS:** brew install openjdk@17 Alternatively, download from [Eclipse Adoptium](https://adoptium.net/). ## Set up pom.xml dependencies Now we can specify which dependencies we need to be able to run a test. Create a new file called `pom.xml` and make sure to define at least the following dependencies: - `com.codeborne:selenide``org.testng:testng``org.seleniumhq.selenium:selenium-java` 4.0.0 testingbot-testng-selenide com.testingbot 1.0-SNAPSHOT jar testingbot_selenide_testng An example project to run Selenide + TestNG tests on TestingBot's browser grid 17 17 com.codeborne selenide 7.4.2 test org.testng testng 7.10.2 test org.seleniumhq.selenium selenium-java 4.39.0 test maven-compiler-plugin 3.13.0 ${maven.compiler.source} ${maven.compiler.target} org.apache.maven.plugins maven-surefire-plugin 2.12.4 classes 40 false ## Define TestingBot driver We need to define a base class to let Selenide know how to connect to the TestingBot browser grid. package com.testingbotdemo.selenium.selenide.drivers; import java.net.URL; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import com.codeborne.selenide.WebDriverRunner; public class TestingBotDriver { private RemoteWebDriver driver; @BeforeMethod(alwaysRun = true) public void setUp() throws Exception { String username = System.getenv("TESTINGBOT_KEY") == null ? "TESTINGBOT_KEY" : System.getenv("TESTINGBOT_KEY"); String accesskey = System.getenv("TESTINGBOT_SECRET") == null ? "TESTINGBOT_SECRET" : System.getenv("TESTINGBOT_SECRET"); ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Selenide Example"); options.setCapability("tb:options", tbOptions); try { String gridURL = "https://" + username + ":" + accesskey + "@hub.testingbot.com/wd/hub"; driver = new RemoteWebDriver(new URL(gridURL), options); WebDriverRunner.setWebDriver(driver); } catch (MalformedURLException e) { e.printStackTrace(); throw new RuntimeException("Invalid URL provided for TestingBot hub", e); } } @AfterMethod(alwaysRun = true) public void tearDown() throws Exception { if (driver != null) { driver.quit(); } } } The `ChromeOptions` class is used to define which remote browser you want to use on TestingBot. ## Test Now we can create our first Selenide test. Create a new class that extends from `TestingBotDriver` with the following contents: package com.testingbotdemo.selenium.selenide.drivers; import static com.codeborne.selenide.Selenide.*; import static com.codeborne.selenide.Condition.*; import org.openqa.selenium.By; import org.testng.Assert; import org.testng.annotations.Test; public class ExampleTest extends TestingBotDriver { @Test public void test() throws Exception { open("https://testingbot.com"); $("body").shouldHave(text("TestingBot")); } } ## Run Selenide test You can now run the Selenide test from the commandline: TB_KEY={..your-key..} TB_SECRET={..your-secret-..} mvn test The Selenide test will run on a remote TestingBot browser. Once the test has finished, you will be able to see the result, together with a video and logs in the TestingBot dashboard. ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a TestNG test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: package com.testingbotdemo.selenium.selenide.drivers; import java.net.URL; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import com.codeborne.selenide.WebDriverRunner; public class TestingBotDriver { private RemoteWebDriver driver; @BeforeMethod(alwaysRun = true) public void setUp() throws Exception { String username = System.getenv("TESTINGBOT_KEY") == null ? "TESTINGBOT_KEY" : System.getenv("TESTINGBOT_KEY"); String accesskey = System.getenv("TESTINGBOT_SECRET") == null ? "TESTINGBOT_SECRET" : System.getenv("TESTINGBOT_SECRET"); ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Tunnel Selenide Example"); options.setCapability("tb:options", tbOptions); String gridURL = "http://localhost:4445/wd/hub"; driver = new RemoteWebDriver(new URL(gridURL), options); WebDriverRunner.setWebDriver(driver); } @AfterMethod(alwaysRun = true) public void tearDown() throws Exception { if (driver != null) { driver.quit(); } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run a test on different browsers at the same time, you can run the same `mvn test` command multiple times in parallel, each with a different browser/capability environment variable. For example, assuming you define the desired capabilities with environment variables: ChromeOptions options = new ChromeOptions(); options.setPlatformName(System.getenv("CAPABILITY_PLATFORMNAME")); options.setBrowserVersion(System.getenv("CAPABILITY_BROWSERVERSION")); Now you can run the same test on multiple browsers simultaneously: mvn test -DCAPABILITY_BROWSERNAME=chrome -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=WIN10 mvn test -DCAPABILITY_BROWSERNAME=safari -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=SONOMA ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use the TestingBot [API](https://testingbot.com/support/api). TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) to facilitate interacting with the TestingBot API. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once you've included this client with your tests, you will be able to send back the test status and other meta-data to TestingBot: import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @AfterMethod public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java/testng # TestNG Automated Testing See our [TestNG example repository](https://github.com/testingbot/java-testng-example) for a simple example on how to run TestNG tests on TestingBot. TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. You can find more info about TestNG on the [TestNG website](https://testng.org/#_testng_documentation). To run your first test with TestNG, please follow the simple example below. ### Example code import java.net.URL; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class TestingBotTest { private WebDriver driver; @BeforeClass public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "My TestNG Test"); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URL("https://api_key:api_secret@hub.testingbot.com/wd/hub"), options); } @Test public void testSimple() throws Exception { driver.get("https://testingbot.com/"); String searchHeader = driver.findElement(By.cssSelector("H1")) .getText().toLowerCase(); Assert.assertTrue(searchHeader.contains("automated")); } @AfterClass public void tearDown() throws Exception { driver.quit(); } } ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** WebDriver driver = new FirefoxDriver(); **After:** FirefoxOptions options = new FirefoxOptions(); WebDriver driver = new RemoteWebDriver( new URL("https://key:secret@hub.testingbot.com/wd/hub"), options ); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a TestNG test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: import java.net.URL; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class TestingBotTest { private WebDriver driver; @BeforeClass public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Tunnel Test"); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URL("http://api_key:api_secret@localhost:4445/wd/hub"), options); } @Test public void testSimple() throws Exception { driver.get("http://localhost:3000"); // Your internal website String header = driver.findElement(By.cssSelector("H1")) .getText().toLowerCase(); Assert.assertTrue(header.contains("welcome")); } @AfterClass public void tearDown() throws Exception { driver.quit(); } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run a test on different browsers at the same time, you will need to create a `testng.xml` file and create a testcase that uses parameters (`org.testng.annotations.Parameters`). Please see the example below: package tb; import org.testng.annotations.Test; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.Assert; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.FileUtils; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; public class TestCase { private WebDriver driver; @BeforeClass @org.testng.annotations.Parameters(value={"browser","version","platform"}) public void setUp(String browser, String version, String platform) throws Exception { ChromeOptions options = new ChromeOptions(); options.setCapability("browserName", browser); options.setCapability("browserVersion", version); options.setCapability("platformName", platform); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Parallel TestNG"); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URL("https://api_key:api_secret@hub.testingbot.com/wd/hub"), options); } @Test public void testSimple() throws Exception { driver.get("https://www.google.com"); System.out.println("Page title is: " + driver.getTitle()); Assert.assertEquals("Google", driver.getTitle()); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); try { FileUtils.copyFile(srcFile, new File("Screenshot.png")); } catch (IOException e) { e.printStackTrace(); } } @AfterClass public void tearDown() throws Exception { driver.quit(); } } Now you need to create a `testng.xml` file which will provide the test cases with parameters (browser combinations): ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you need to use our [API](https://testingbot.com/support/api). TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) for using the TestingBot API. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once included with your tests, you can send back test status and other meta-data to TestingBot: import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @AfterClass public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## More TestNG resources Looking for more information regarding TestNG? See our [TestNG with Selenium](https://testingbot.com/resources/articles/testng-selenium) article for more information on what TestNG supports, including assertions and annotations. ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/java/testng-cucumber # TestNG & Cucumber Automated Testing Please consult the [TestNG + Cucumber example repository](https://github.com/testingbot/java-testng-cucumber-example) to see a simple example on how to run TestNG & Cucumber tests on TestingBot. TestNG is a powerful testing framework inspired by JUnit and NUnit but with more flexible and robust features. It is widely used by Java enthusiast for testing because it offers powerful annotations, test configuration and parallel testing. Cucumber is a popular tool for Behavior-Driven Development (BDD), allowing test scripts to be written in a human-readable format using the Gherkin language. Because Cucumber uses this natural-like language, it enables collaboration between technical and non-technical team members. To get started, let's go through all the necessary steps required to run your first test with TestNG and Cucumber on TestingBot. ## Prerequisites Let's start with making sure Java is available on your system. **For Windows:** - You can download Java for Windows from [Java.com](https://www.java.com/en/download/manual.jsp) - Run the installer and follow the setup wizard to install Java. **For Linux (Debian/Ubuntu):** sudo apt-get install openjdk-17-jdk **For macOS:** brew install openjdk@17 Alternatively, download from [Eclipse Adoptium](https://adoptium.net/). ## Set up pom.xml dependencies Now we can specify which dependencies we need to be able to run a test. Create a new file called `pom.xml` and make sure to define at least the following dependencies: - `io.cucumber:cucumber-java``io.cucumber:cucumber-testng``org.testng:testng``org.seleniumhq.selenium:selenium-java` 4.0.0 testingbot-testng-cucumber com.testingbot 1.0-SNAPSHOT jar testingbot_cucumber_testng An example project to run Cucumber + TestNG tests on TestingBot's browser grid io.cucumber cucumber-java 7.18.1 io.cucumber cucumber-testng 7.18.1 org.testng testng 7.10.2 test org.seleniumhq.selenium selenium-java 4.39.0 test maven-compiler-plugin 3.13.0 17 17 org.apache.maven.plugins maven-surefire-plugin 2.12.4 classes 40 false ## Project Structure Now we need to create a folder structure that will contain the `.feature` files and step definitions. Create a folder for the `.feature` files: mkdir -p src/test/resources/features We can also define directories for the step definitions, driver and the TestingBot runner class: mkdir -p src/test/java/com/testingbotdemo/selenium/cucumber/{definitions,drivers,runners} ## Define TestingBot driver Now we can define a custom driver that will run the tests on the TestingBot grid: package com.testingbotdemo.selenium.cucumber.drivers; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; public class TestingBotDriver { public static WebDriver getDriver() { String username = System.getenv("TESTINGBOT_KEY") == null ? "TESTINGBOT_KEY" : System.getenv("TESTINGBOT_KEY"); String accesskey = System.getenv("TESTINGBOT_SECRET") == null ? "TESTINGBOT_SECRET" : System.getenv("TESTINGBOT_SECRET"); ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Cucumber Example"); options.setCapability("tb:options", tbOptions); try { String gridURL = "https://" + username + ":" + accesskey + "@hub.testingbot.com/wd/hub"; return new RemoteWebDriver(new URL(gridURL), options); } catch (MalformedURLException e) { e.printStackTrace(); throw new RuntimeException("Invalid URL provided for TestingBot hub", e); } } } We will need to make sure to later specify the `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` environment variables to authenticate and run tests on the TestingBot remote browser grid. The `ChromeOptions` class is used to define which remote browser we would like to run this Cucumber test on. ## Test Runner Next, let's create a Test runner class that will use the `CucumberOptions` annotation to let Cucumber know where to find the feature files and the step definitions. package com.testingbotdemo.selenium.cucumber.runners; import io.cucumber.testng.AbstractTestNGCucumberTests; import io.cucumber.testng.CucumberOptions; @CucumberOptions( features = "src/test/resources/features", glue = "com.testingbotdemo.selenium.cucumber.definitions" ) public class TestRunner extends AbstractTestNGCucumberTests { } ## Step Definitions Finally, we need to define the step definitions. This is the logic that converts the Gherkin syntax to actual code. The code that we will use will interact with the [Driver class](https://testingbot.com#driver) we defined. package com.testingbotdemo.selenium.cucumber.definitions; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import org.openqa.selenium.By; import org.testng.Assert; import com.testingbotdemo.selenium.cucumber.drivers.TestingBotDriver; import org.openqa.selenium.WebDriver; public class StepDefinitions { WebDriver driver = TestingBotDriver.getDriver(); @Given("I open Google") public void i_open_google() { driver.get("https://www.google.com"); } @When("I search for {string}") public void i_search_for(String query) { driver.findElement(By.name("q")).sendKeys(query); driver.findElement(By.name("btnK")).submit(); } @Then("I should see results") public void i_should_see_results() { Assert.assertTrue(driver.getTitle().contains("Google")); driver.quit(); } } ## Run Cucumber test You can now run the Cucumber test: TB_KEY={..your-key..} TB_SECRET={..your-secret-..} mvn test The test will run on a remote TestingBot browser. Once the test has finished, you will be able to see the result, together with a video and logs in the TestingBot dashboard. ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a TestNG test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: package com.testingbotdemo.selenium.cucumber.drivers; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Map; public class TestingBotDriver { public static WebDriver getDriver() { String username = System.getenv("TESTINGBOT_KEY") == null ? "TESTINGBOT_KEY" : System.getenv("TESTINGBOT_KEY"); String accesskey = System.getenv("TESTINGBOT_SECRET") == null ? "TESTINGBOT_SECRET" : System.getenv("TESTINGBOT_SECRET"); ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); Map tbOptions = new HashMap<>(); tbOptions.put("name", "Tunnel Cucumber Example"); options.setCapability("tb:options", tbOptions); try { String gridURL = "http://" + username + ":" + accesskey + "@localhost:4445/wd/hub"; return new RemoteWebDriver(new URL(gridURL), options); } catch (MalformedURLException e) { e.printStackTrace(); throw new RuntimeException("Invalid URL provided for TestingBot hub", e); } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run a test on different browsers at the same time, you can run the same `mvn test` command multiple times in parallel, each with a different browser/capability environment variable. For example, assuming you define the desired capabilities with environment variables: ChromeOptions options = new ChromeOptions(); options.setPlatformName(System.getenv("CAPABILITY_PLATFORMNAME")); options.setBrowserVersion(System.getenv("CAPABILITY_BROWSERVERSION")); Now you can run the same test on multiple browsers simultaneously: mvn test -DCAPABILITY_BROWSERNAME=chrome -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=WIN10 mvn test -DCAPABILITY_BROWSERNAME=safari -DCAPABILITY_BROWSERVERSION=latest -DCAPABILITY_PLATFORMNAME=SONOMA ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use the TestingBot [API](https://testingbot.com/support/api). TestingBot has a [Java client](https://github.com/testingbot/testingbot-java) to facilitate interacting with the TestingBot API. **Maven:** com.testingbot testingbotrest 1.0.10 **Gradle:** implementation 'com.testingbot:testingbotrest:1.0.10' Once you've included this client with your tests, you will be able to send back the test status and other meta-data to TestingBot: import com.testingbot.comingbotrest.TestingbotREST; import java.util.HashMap; import java.util.Map; @After public void tearDown() throws Exception { TestingbotREST api = new TestingbotREST("key", "secret"); Map data = new HashMap<>(); data.put("success", "1"); data.put("name", "My Test"); api.updateTest(driver.getSessionId().toString(), data); driver.quit(); } ## Other Java Framework examples - [JUnit](https://testingbot.com/support/web-automate/selenium/java/junit) JUnit is a unit testing framework for the Java programming language. - [Parallel JUnit](https://testingbot.com/support/web-automate/selenium/java/parallel-junit) By running multiple JUnit tests at the same time you can cut down on overall test time. - [TestNG](https://testingbot.com/support/web-automate/selenium/java/testng) TestNG is a framework similar to JUnit and NUnit, which supports some additional commands and features. - [TestNG + Cucumber](https://testingbot.com/support/web-automate/selenium/java/testng-cucumber) Run tests with TestNG and BDD Cucumber. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/javascript # Javascript Unit Testing It's possible to run your javascript unit tests on [our cloud of browsers](https://testingbot.com/support/web-automate/browsers). Instead of running your javascript test on a couple of browsers, you can run your tests on dozens of different browsers/versions/platforms all in parallel on our grid. ## Javascript Test Frameworks Below is an overview of the javascript unit testing frameworks, each with an example. Other javascript testing frameworks not listed here also do work with TestingBot, we just don't have any example yet. ### Pick a Javascript test framework - [Karma](https://testingbot.com/support/web-automate/selenium/javascript/karma) Javascript testing with the Karma test runner. - [Intern](https://testingbot.com/support/web-automate/selenium/javascript/intern) Intern runs your javascript tests with full code coverage reporting. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/javascript/karma # Javascript unit testing with Karma We've prepared an example with full TestingBot integration which is easy to set up and run. With our integrated `karma-testingbot-launcher`, you can easily run tests with Karma on TestingBot. Our launcher will automatically start/stop a tunnel and report back the test results to us. ## Installing the example Make sure you have installed both `git` and `NodeJS`. Then proceed to clone our [karma-testingbot-example](https://github.com/testingbot/karma-testingbot-example) with the follow commands: git clone https://github.com/testingbot/karma-testingbot-example.git cd karma-testingbot-example Once that's installed, please run the follow command to set up the example: sudo npm install -g karma-cli && npm install ## Run Karma test with our [karma-testingbot-launcher](https://github.com/karma-runner/karma-testingbot-launcher) plugin In the example's directory, you'll find a file `karma.conf-testingbot.js` which contains a "customLaunchers" variable with multiple browsers defined. This is the place where you specify on which browsers you want your test to run. To actually run the test on TestingBot, we first need to specify the `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` environment variables, which you can find in our member area. export TESTINGBOT_KEY=YOUR_KEY export TESTINGBOT_SECRET=YOUR_SECRET Now you're ready to run the test on TestingBot. To start the test, run the following command: karma start karma.conf-testingbot.js This will download and start our [TestingBot Tunnel](https://testingbot.com/support/tunnel), run your test and report back the result. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/javascript/intern # NodeJS with Intern With Intern you can run Javascript unit tests on TestingBot's browser grid. Run your javascript test on all our [browsers](https://testingbot.com/support/web-automate/browsers) in the cloud. ## Installing the example Make sure you have installed `git` and `NodeJS`. Then proceed to clone our [intern\_example](https://github.com/testingbot/intern_example) with the follow commands: git clone https://github.com/testingbot/intern_example.git cd intern_example Once that's installed, please run the follow command to set up the example: npm install intern --save-dev ## Run Intern test on TestingBot In the `tests/intern.js` file you'll find environment variables where you can indicate on which browsers you want your test to run on via TestingBot. To actually run the test on TestingBot, we first need to specify the TestingBot `key` and `secret` in `tests/intern.js`. You need to specify these in the `webdriver` and `tunnelOptions` variables. apiKey: "YOUR_KEY", apiSecret: "YOUR_SECRET" Now you're ready to run the test on TestingBot. To start the test, run the following command: ./node_modules/.bin/intern-runner config=tests/intern This will download and start our [TestingBot Tunnel](https://testingbot.com/support/tunnel), run your test and report back the result to TestingBot. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ide # Selenium IDE Selenium IDE is a [Chrome addon](https://chrome.google.com/webstore/detail/selenium-ide/mooikfkahbdckldjjndioackbalphokd) / [Firefox addon](https://www.selenium.dev/selenium-ide/) which you can install to record and run browser tests. Once you've installed the plugin, you can record an entire flow from your own browser. You can record every interaction you do on a website and add assertions in your test. ## What can Selenium IDE do for me? Here's one example: you can record yourself clicking through various pages on your website. During this recording, you can right click various elements and indicate that these need to be present, or contain a specific value. ![Selenium IDE screenshot](https://testingbot.com/assets/wizard/ide-2e7510cfbc2b24f20c4483cb4045179fdf5036cdb391ae72ad470f8f360a3a18.jpg) Once you've finished this recording, you can choose to instantly playback the recording. The IDE will mimick your recorded behavior together with the assertions you've recorded. ## TestingBot integration with Selenium IDE When you finished recording a test, you can choose to save the test from the Selenium IDE. The saved file (with a `.side` extension) can be uploaded into [our TestLab](https://testingbot.com/support/web-automate/codeless-automation/add-test). In our TestLab, you can indicate on which browsers and platforms the test needs to run. You can schedule tests and indicate if you would like to be alerted when a test fails. ## Advanced: Selenium SIDE runner with TestingBot It's possible to run tests recorded with Selenium IDE via the [selenium-side-runner](https://github.com/SeleniumHQ/selenium-ide/tree/v3/packages/selenium-side-runner) commandline program on TestingBot. Simply save a recorded test as a `.side` file and run it like this: npm install -g selenium-side-runner selenium-side-runner --server https://key:secret@hub.testingbot.com/wd/hub -c "browserName=chrome platform=WIN10 version=latest" *.side Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/katalon-studio # Katalon Studio See our [Katalon Studio Plugin](https://testingbot.com/support/integrations/katalon-studio) for easy integration between TestingBot and Katalon Studio. [Katalon Studio](https://www.katalon.com/katalon-studio/) allows testers to easily create, manage and run automated tests. Below is some more information on how to run your recorded tests via Katalon Studio on TestingBot and take advantage of the [large collection of browsers and mobile devices](https://testingbot.com/support/web-automate/browsers) available on the TestingBot cloud. ## Configuration For this tutorial, we assume you've already created or recorded a web/mobile test with Katalon Studio. To connect with TestingBot, you will need to configure Katalon Studio to pass the correct configuration to TestingBot. Go to **Project \> Settings** then choose the **Desired Capabilities** option and click **Remote**. Fill in the correct **Remote server URL** : `https://api_key:api_secret@hub.testingbot.com/wd/hub` ![katalon studio with TestingBot](https://testingbot.com/assets/support/katalon-bc59f7c086cd9d849763e6b6846c8a5bfbe38ec5804b8905fae42da5ba97fe6f.png) Fill in the `browserName`, `version` and `platform` or any [other desired capabilities](https://testingbot.com/support/web-automate/selenium/test-options) you want to use. ## Run Katalon Studio test on TestingBot To run the recorded test on TestingBot, click **Action \> Run** and then **Remote**. ![run Katalone test on TestingBot](https://testingbot.com/assets/support/katalon-remote-d0844ef224eb68c19a3cbd28c81dac618fa4d77587a3ff3ff70593e1dfa59cf4.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python ### Python Examples: - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) - [SeleniumBase](https://testingbot.com/support/web-automate/selenium/python/seleniumbase) # Python Automated Testing Before you can do any kind of integration testing with Python, let's first start with making sure Python is available on your system. **For Windows:** - Download the latest python installer for Windows: [Python Releases for Windows](https://www.python.org/downloads/windows/) - Run the installer and follow the setup wizard to install Python. **For Linux/macOS:** - Run `python --version` to see which Python version is currently installed, make sure it is 2.5.X or above. - macOS, Ubuntu and most other Linux distros come with Python pre-installed. ## Installation [![Video tutorial on how to run a Python Automated Test on TestingBot](https://testingbot.com/assets/videos/python-automated-c0afd41f66658429632dbc218f3948be42b059eeae854abf1093d20487431dee.webp)](https://testingbot.com#) about:blank With TestingBot you can easily run your automated tests with [any Python testing framework](https://testingbot.com#list), here's a simple example: sudo easy_install pip pip install -U selenium pip install testingbotclient import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class TestTestingBotClient(unittest.TestCase): def setUp(self): desired_cap = { 'platform': 'Windows', 'browserName': 'chrome', 'version': 'latest-1' } self.driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) def test_google_example(self): self.driver.get("https://www.google.com") if not "Google" in self.driver.title: raise Exception("Unable to load google page!") elem = self.driver.find_element_by_name("q") elem.send_keys("TestingBot") elem.submit() def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() This test will start a Firefox browser on Windows in our cloud, go to Google, and search for TestingBot. It will then output the title. Once the test has finished, the `tb_client` library will send back the test's success state and name to TestingBot, so you have a nice overview of your tests by name and success state in our member dashboard. Make sure to always stop your test (`driver.quit()`), otherwise it will continue running, leading to a timeout. ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = webdriver.Firefox() **After:** driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Python test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class TestTestingBotClient(unittest.TestCase): def setUp(self): desired_cap = {'platform': 'Windows', 'browserName': 'chrome', 'version': 'latest-1' } self.driver = webdriver.Remote( command_executor='http://key:secret@localhost:4445/wd/hub', desired_capabilities=desired_cap) def test_google_example(self): self.driver.get("https://www.google.com") if not "Google" in self.driver.title: raise Exception("Unable to load google page!") elem = self.driver.find_element_by_name("q") elem.send_keys("TestingBot") elem.submit() def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using Nose and MultiProcessing, which makes it very easy to run multiple Python tests simultaneously: pip install nose==0.11 pip install multiprocessing nosetests --processes= ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Other Python Testing Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." - [SeleniumBase](https://testingbot.com/support/web-automate/selenium/python/seleniumbase) SeleniumBase is a Python package that simplifies Selenium testing. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/pyunit # PyUnit Automated Testing See our [PyUnit example repository](https://github.com/testingbot/testingbot_pyunit) for a simple example on how to run PyUnit tests on TestingBot. Let's start with making sure Python is available on your system. **For Windows:** - Download the latest python installer for Windows: [Python Releases for Windows](https://www.python.org/downloads/windows/) - Run the installer and follow the setup wizard to install Python. **For Linux/macOS:** - Run `python --version` to see which Python version is currently installed, make sure it is 2.5.X or above. - macOS, Ubuntu and most other Linux distros come with Python pre-installed. ## Installation First, make sure you have installed the correct Python Packages: sudo easy_install pip sudo pip install selenium sudo pip install testingbotclient You are now ready to start testing with our Selenium grid. ### Example code import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class Selenium2TestingBot(unittest.TestCase): def setUp(self): desired_capabilities = webdriver.DesiredCapabilities.FIREFOX desired_capabilities['version'] = 'latest' desired_capabilities['platform'] = 'WINDOWS' desired_capabilities['name'] = 'Testing Selenium with Python' self.driver = webdriver.Remote( desired_capabilities=desired_capabilities, command_executor="http://key:secret@hub.testingbot.com/wd/hub" ) self.driver.implicitly_wait(30) def test_google(self): self.driver.get('https://www.google.com') assert "Google" in self.driver.title def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = webdriver.Firefox() **After:** driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PyUnit test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class Selenium2TestingBot(unittest.TestCase): def setUp(self): desired_capabilities = webdriver.DesiredCapabilities.FIREFOX desired_capabilities['version'] = 'latest' desired_capabilities['platform'] = 'WINDOWS' desired_capabilities['name'] = 'Testing Selenium with Python' self.driver = webdriver.Remote( desired_capabilities=desired_capabilities, command_executor="http://key:secret@localhost:4445/wd/hub" ) self.driver.implicitly_wait(30) def test_google(self): self.driver.get('https://www.google.com') assert "Google" in self.driver.title def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Example code (Selenium WebDriver Parallel testing) from threading import Thread from selenium import webdriver import time API_KEY = "KEY" API_SECRET = "SECRET" def get_browser(caps): return webdriver.Remote( desired_capabilities=caps, command_executor="http://%s:%s@hub.testingbot.com/wd/hub" % (API_KEY, API_SECRET) ) browsers = [ { "platform":"WINDOWS", "browserName" : "firefox", "version" : "latest-2", "name" : "FF" }, { "platform":"WINDOWS", "browserName" : "firefox", "version" : "latest", "name" : "FF" }, { "platform":"LINUX", "browserName" : "chrome", "name" : "Chrome" }, { "platform":"MAC", "browserName" : "safari", "version" : "latest", "name" : "Safari" } ] browsers_waiting = [] def get_browser_and_wait(browser_data): print "starting %s" % browser_data["name"] browser = get_browser(browser_data) browser.get("https://testingbot.com") browsers_waiting.append({ "data" : browser_data, "driver" : browser }) print "%s ready" % browser_data["name"] while len(browsers_waiting) < len(browsers): print "browser %s sending heartbeat while waiting" % browser_data["name"] browser.get("https://testingbot.com") time.sleep(3) thread_list = [] for i, browser in enumerate(browsers): t = Thread(target=get_browser_and_wait, args=[browser]) thread_list.append(t) t.start() for t in thread_list: t.join() print "all browsers ready" for i, b in enumerate(browsers_waiting): print "browser %s's title: %s" % (b["data"]["name"], b["driver"].title) b["driver"].quit() ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Other Python Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/lettuce # BDD with Python, Lettuce and WebDriver **Note:** Lettuce is no longer actively maintained. Consider using [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) or [pytest-bdd](https://pytest-bdd.readthedocs.io/) for new projects. Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. To get started, make sure you have installed these packages with `pip`: pip install lettuce lettuce_webdriver nose You are now ready to create your first story and run it on our Selenium grid. Run the test with: lettuce ### Example feature (features/google.feature) Feature: Go to google Scenario: Visit Google Given I go to "https://www.google.com/" When I fill in field with class "gsfi" with "testingbot" Then I should see "testingbot.com" within 2 second ### Example steps (features/steps.py) from lettuce import * from lettuce_webdriver.util import assert_false from lettuce_webdriver.util import AssertContextManager from selenium.webdriver.common.by import By def find_field_by_class(browser, attribute): xpath = "//input[@class='%s']" % attribute elems = browser.find_elements(By.XPATH, xpath) return elems[0] if elems else False @step('I fill in field with class "(.*?)" with "(.*?)"') def fill_in_textfield_by_class(step, field_name, value): with AssertContextManager(step): text_field = find_field_by_class(world.browser, field_name) text_field.clear() text_field.send_keys(value) ### Example terrain.py from lettuce import before, world from selenium import webdriver from selenium.webdriver.firefox.options import Options import lettuce_webdriver.webdriver @before.all def setup_browser(): options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'Testing Selenium with Lettuce' }) world.browser = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = webdriver.Firefox() **After:** from selenium.webdriver.firefox.options import Options options = Options() # set capabilities from picker below driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Lettuce Python test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: ### Example terrain.py from lettuce import before, world from selenium import webdriver from selenium.webdriver.firefox.options import Options import lettuce_webdriver.webdriver @before.all def setup_browser(): options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'Testing Selenium with Lettuce' }) world.browser = webdriver.Remote( command_executor='http://localhost:4445/wd/hub', options=options ) ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using pytest with pytest-xdist, which makes it easy to run multiple Python tests simultaneously: pip install pytest pytest-xdist pytest -n ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Other Python Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/behave # BDD with Python, Behave and WebDriver See our [Behave example repository](https://github.com/testingbot/python-behave-example) for a simple example on how to run Behave tests in parallel on TestingBot. Behave is a Python BDD (Behavior Driven Development) framework which makes it easy to write tests (bdd tests) in a natural language style. To get started, make sure you have installed Behave: pip install behave You are now ready to create your first story and run it on our Selenium grid. Run the test with: behave ### Example feature (features/google.feature) This feature file needs to be added to the features directory. Feature: testing google Scenario: visit google and check When we visit google Then it should have a title "Google" ### Example steps (features/steps/steps.py) @when('we visit google') def step(context): context.browser.get('https://www.google.com') @then('it should have a title "Google"') def step(context): assert context.browser.title == "Google" ### Example features/environment.py from selenium import webdriver def before_all(context): desired_capabilities = webdriver.DesiredCapabilities.FIREFOX desired_capabilities['version'] = 'latest' desired_capabilities['platform'] = 'WINDOWS' desired_capabilities['name'] = 'Testing Selenium with Behave' desired_capabilities['client_key'] = 'key' desired_capabilities['client_secret'] = 'secret' context.browser = webdriver.Remote( desired_capabilities=desired_capabilities, command_executor="https://hub.testingbot.com/wd/hub" ) def after_all(context): context.browser.quit() ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = webdriver.Firefox() **After:** driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Behave WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: ### Example features/environment.py from selenium import webdriver def before_all(context): desired_capabilities = webdriver.DesiredCapabilities.FIREFOX desired_capabilities['version'] = 'latest' desired_capabilities['platform'] = 'WINDOWS' desired_capabilities['name'] = 'Testing Selenium with Behave' desired_capabilities['client_key'] = 'key' desired_capabilities['client_secret'] = 'secret' context.browser = webdriver.Remote( desired_capabilities=desired_capabilities, command_executor="http://localhost:4445/wd/hub" ) def after_all(context): context.browser.quit() ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Other Python Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/helium # Helium Automated Browser Testing Helium is a tool that makes it easy to test websites and automate browsers. It's designed to be very simple to use and integrate. Helium can be used as a Java or Python library and integrates with the Selenium Framework. ## Setting up Helium There's a very good tutorial on how to set up Helium on the [Helium Repository](https://github.com/mherrmann/selenium-python-helium) page. Once you've got everything set up, it's easy to run your first test with Helium on TestingBot: ## Running your first test Below is an example on how to run a simple test on Firefox. When the test has finished, the test name and success state is sent to TestingBot so you can see the test success/failures in our dashboard. To send the test success state back to us, please install our Python plugin: pip install testingbotclient **Python Example:** import sys import unittest from selenium import webdriver from selenium.webdriver.firefox.options import Options from helium import * from testingbotclient import TestingBotClient class HeliumOnTestingBot(unittest.TestCase): def setUp(self): options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Test' }) self.driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) set_driver(self.driver) def test_tb(self): go_to('https://testingbot.com') click('Log in') write("my@email.com", into="Email") write("myPassword", into="Password") click(Button('Sign in')) def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('API_KEY', 'API_SECRET') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() **Java Example:** import org.junit.After; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import static junit.framework.Assert.assertEquals; import static com.heliumhq.API.*; public class WebDriverTest { private WebDriver driver; @Before public void setUp() throws Exception { FirefoxOptions options = new FirefoxOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); tbOptions.put("name", "My First Test"); options.setCapability("tb:options", tbOptions); this.driver = new RemoteWebDriver( new URL("https://hub.testingbot.com/wd/hub"), options); setDriver(this.driver); } @Test public void testWithTestingBot() throws Exception { goTo("https://testingbot.com"); click("Log in"); assertEquals("Online Selenium Testing - Log in to manage your unit tests.", getDriver().getTitle()); write("user12345", into("Email:")); write("user12345", into("Password:")); click(Button("Sign in")); } @After public void tearDown() throws Exception { driver.quit(); } } ## Specifying the operating system, browser and version To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. **Before** driver = webdriver.Firefox() **After** from selenium.webdriver.firefox.options import Options options = Options() # set capabilities from picker below driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options) ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## More Information More information regarding Helium is available on the [Helium Repository](https://github.com/mherrmann/selenium-python-helium). ## Other Python Testing Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." - [SeleniumBase](https://testingbot.com/support/web-automate/selenium/python/seleniumbase) SeleniumBase is a Python package that simplifies Selenium testing. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/pytest # PyTest Automated Testing See our [PyTest Selenium Example](https://github.com/testingbot/Python-PyTest-Selenium) for a simple example on how to run PyTest tests on TestingBot. Let's start with making sure Python is available on your system. **For Windows:** - Download the latest python installer for Windows: [Python Releases for Windows](https://www.python.org/downloads/windows/) - Run the installer and follow the setup wizard to install Python. **For Linux/macOS:** - Run `python --version` to see which Python version is currently installed, make sure it is 2.5.X or above. - macOS, Ubuntu and most other Linux distros come with Python pre-installed. ## Installation First, make sure you have installed `pytest-selenium`: pip install pytest-selenium You are now ready to start testing with our Selenium grid. ### Setup credentials To authenticate with our Selenium grid, you'll need to configure PyTest to pass your credentials. You can either do this via environment variables, or by using a config file. - **Environment variables** : export TESTINGBOT_KEY=key export TESTINGBOT_SECRET=secret - **Config file** : Create a `~/.testingbot` file with this content: [credentials] key = key secret = secret ### Example code Save the example in a file called `test_sample.py`. (Important: the filename should start with `test_`) import pytest @pytest.mark.usefixtures('driver') class TestSample: def test_sample(self, driver): driver.get('https://google.com/ncr') title = "Google" assert title == driver.title To run this test, run this command: pytest --driver TestingBot --capability browserName chrome --capability version latest --capability platform WIN10 This will run the test on the latest version of Chrome on Windows 10. To run on different platforms, please see the configuration option below. PyTest Selenium provides built-in support for TestingBot. See the [PyTest + TestingBot documentation](https://pytest-selenium.readthedocs.io/en/latest/user_guide.html#testingbot). ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** pytest test_sample.py **After:** pytest --driver TestingBot --capability browserName chrome --capability version latest --capability platform WIN10 ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PyTest WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret -i pyTunnel 2. Run your test and specify the `tunnelIdentifier` which we've added in the step above (`-i pyTunnel`) pytest --driver TestingBot --capability browserName chrome --capability version latest --capability platform WIN10 --capability tunnelIdentifier pyTunnel ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. You can use PyTest's `-n` option to run multiple tests at the same time or use [PyTest Parallel](https://pypi.org/project/pytest-parallel/) (recommended way). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(self.driver.session_id, status_message=.., passed=1|0, build=.., name=..) ## Other Python Framework examples - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. - [Pylenium](https://testingbot.com/support/web-automate/selenium/python/pylenium) Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/pylenium # Pylenium Pylenium is a Python package, its mission: "Bring the best of Selenium, Cypress and Python into one package." To get started, please make sure you have **python3** installed. Then install the package: pip install pyleniumio ## Configuring capabilities To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. **Before** driver = webdriver.Firefox() **After** driver = webdriver.Remote( command_executor='https://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal/Staged Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Lettuce Python test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: ### Example terrain.py from lettuce import before, world from selenium import webdriver import lettuce_webdriver.webdriver @before.all def setup_browser(): desired_capabilities = webdriver.DesiredCapabilities.FIREFOX desired_capabilities['version'] = 'latest' desired_capabilities['platform'] = 'WINDOWS' desired_capabilities['name'] = 'Testing Selenium with Lettuce' world.browser = webdriver.Remote( desired_capabilities=desired_capabilities, command_executor="http://key:secret@localhost:4445/wd/hub" ) ## Other Options We offer many other [test options](https://testingbot.com/support/web-automate/selenium/test-options), for example: disable video recording, specifying a custom Firefox Profile, loading Chrome/Firefox/Safari extensions, running an executable before your test starts, uploading files, ... See our [list of test options](https://testingbot.com/support/web-automate/selenium/test-options) for a full list of options to customize your tests. ## Parallel Testing Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. To run tests in parallel, we recommend using Nose and MultiProcessing, which makes it very easy to run multiple Python tests simultaneously: pip install nose==0.11 pip install multiprocessing nosetests --processes= ## Reporting Test Results As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Python API client](https://github.com/testingbot/testingbotclient) to report back test results. tb = testingbotclient.TestingBotClient(key, secret) tb.tests.update_test(world.browser.session_id, status_message=.., passed=1|0, build=.., name=..) ## Pick a Python test framework - [PyTest](https://testingbot.com/support/web-automate/selenium/python/pytest) PyTest makes it easy to run Selenium tests with Python. - [Behave](https://testingbot.com/support/web-automate/selenium/python/behave) Behave is behaviour-driven development, Python style. - [Lettuce](https://testingbot.com/support/web-automate/selenium/python/lettuce) Lettuce is a Python BDD plugin based on Ruby's Cucumber, offering Gherkin stories. - [PyUnit](https://testingbot.com/support/web-automate/selenium/python/pyunit) PyUnit is the standard unit testing framework module for Python, described as a Python version of JUnit. - [Helium](https://testingbot.com/support/web-automate/selenium/python/helium) Helium is a tool that makes it easy to test websites and automate browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/python/seleniumbase # SeleniumBase Browser Automation Framework SeleniumBase is a Python-based framework that extends Selenium WebDriver, making it easier to write and run automated web tests. SeleniumBase includes many built-in features such as visual testing, screenshot comparisons, and handling of dynamic web content. One of the key highlights of SeleniumBase is its ability to integrate smoothly with popular Python testing frameworks like pytest. This enables parallel test execution, better test organization and improved scalability for larger projects. ## Setting up SeleniumBase To install SeleniumBase, you can use PyPi to install the package: pip install seleniumbase ## Running your first test Once you've installed SeleniumBase, you can create your first test that will connect to a remote TestingBot browser. **Python Example:** from seleniumbase import BaseCase BaseCase.main( __name__ , __file__ ) class DemoSiteTests(BaseCase): def test_demo_site(self): # Open a web page in the active browser window self.open("https://seleniumbase.io/demo_page") # Assert the title of the current web page self.assert_title("Web Testing Page") # Assert that an element is visible on the page self.assert_element("tbody#tbodyId") # Assert that a text substring appears in an element self.assert_text("Demo Page", "h1") You can now run this script on a TestingBot remote browser: pytest test_demo_site.py --server=TB_KEY:TB_SECRET@hub.testingbot.com --port=443 --protocol=https --cap_file=capabilities/cap_file_TB.py The capabilities are passed as a file, in this case an example cap\_file\_TB.py could look like this: platforms: - browserName: chrome browserVersion: latest platformName: WIN11 tb:name: ${BUILD_NUMBER} ## Specifying the operating system, browser and version To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in a capabilities file. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## More Information More information regarding SeleniumBase is available on the [SeleniumBase documentation](https://seleniumbase.io/seleniumbase/utilities/selenium_grid/ReadMe/). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby ### Ruby Examples: - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) # Ruby Automated Testing Let's start with making sure Ruby is available on your system. **For Windows:** - You can download Ruby for Windows from [RubyInstaller](https://rubyinstaller.org/) - Run the installer and follow the setup wizard to install Ruby. **For Linux/macOS:** Download [RVM](https://rvm.io/) and install Ruby: curl -L https://get.rvm.io | bash -s stable --ruby ## Installation [![Video tutorial on How to run Ruby Automated Test on TestingBot](https://testingbot.com/assets/videos/ruby-automated-bf8e6bafdf31a6b815fdafc10a58e85d93b99b8cd4e788fc3ecb6d652f495a3e.webp)](https://testingbot.com#) about:blank With TestingBot you can easily run your automated tests with [any Ruby test framework](https://testingbot.com#frameworks), here's a simple example without any assertions: gem install selenium-webdriver #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "chrome" caps["browserVersion"] = "latest" caps["platformName"] = "WIN10" caps["tb:name"] = "My First Test" http_client = Selenium::WebDriver::Remote::Http::Default.new http_client.read_timeout = 300 # Timeout for responses http_client.open_timeout = 300 # Timeout for opening connections driver = Selenium::WebDriver.for( :remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :options => caps, :http_client => http_client) driver.navigate.to "https://www.google.com/ncr" element = driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit puts driver.title driver.quit This test will start the latest version of Chrome on Windows in our cloud, go to Google, and search for TestingBot. It will then output the title of the page. Make sure to always stop your test (`driver.quit`), otherwise it will continue running, leading to a timeout. ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = Selenium::WebDriver.for :chrome **After:** driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Ruby WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "chrome" caps["browserVersion"] = "latest" caps["platformName"] = "WIN10" caps["tb:name"] = "My First Test" http_client = Selenium::WebDriver::Remote::Http::Default.new http_client.read_timeout = 300 # Timeout for responses http_client.open_timeout = 300 # Timeout for opening connections client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 120 driver = Selenium::WebDriver.for( :remote, :url => "http://API_KEY:API_SECRET@localhost:4445/wd/hub", :options => caps, :http_client => http_client ) driver.navigate.to "https://www.google.com/ncr" element = driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit puts driver.title driver.quit ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To get started, please see the examples on [https://github.com/grosser/parallel\_tests](https://github.com/grosser/parallel_tests) ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/capybara # Capybara Automated Testing See our [Cucumber + Capybara example repository](https://github.com/testingbot/ruby-cucumber-capybara-example). TestingBot supports Selenium testing using Capybara. Before we start with the example, please make sure you have Capybara installed: gem install capybara Now let's start with a simple Capybara test case. # Google Feature Feature: Google Search Functionality Background: Given I am on https://www.google.com/ncr Scenario: Can find search results When I fill in "q" found by "name" with "TestingBot" And I submit Then I should see title "TestingBot - Google Search" # Google Steps Given /^I am on (.*)$/ do |url| visit url end When /^I fill in "([^\"]*)" found by "([^\"]*)" with "([^\"]*)"$/ do |value, type, keys| fill_in(value, :with => keys) end When /^I submit$/ do find_field('q').native.send_key(:enter) end Then /^I should see title "([^\"]*)"$/ do |title| expect(page).to have_title title end ## Integrate with TestingBot Please use this module to run Capybara tests on TestingBot: require "capybara/cucumber" require "selenium/webdriver" require "testingbot" Capybara.default_max_wait_time = 10 Capybara.default_driver = :selenium Before do | scenario | jobname = "#{scenario.name}" Capybara.register_driver :selenium do | app| capabilities = Selenium::WebDriver::Options.chrome capabilities.browser_version = ENV['version'] capabilities.platform_name = ENV['platform'] tb_options = {} tb_options[:name] = jobname tb_options['selenium-version'] = '3.14.0' capabilities.add_option('tb:options', tb_options) url = "https://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@hub.testingbot.com/wd/hub".strip Capybara::Selenium::Driver.new(app, :browser => :remote, :url => url, :capabilities => capabilities) end Capybara.session_name = "#{jobname} - #{ENV['platform']} - " + "#{ENV['browserName']} - #{ENV['version']}" @driver = Capybara.current_session.driver @session_id = @driver.browser.session_id puts "TestingBotSessionId=#{@session_id} job-name=#{jobname}" end After do | scenario | @driver.quit api = TestingBot::Api.new(ENV['TB_KEY'], ENV['TB_SECRET']) if scenario.exception api.update_test(@session_id, { :success => false }) else api.update_test(@session_id, { :success => true }) end Capybara.use_default_driver end This module uses a Rake file which contains the browsers we want to run the test on: **Rakefile** : def run_tests(platform, browser, version, junit_dir) system("platform=\"#{platform}\" browserName=\"#{browser}\" version=\"#{version}\" JUNIT_DIR=\"#{junit_dir}\" parallel_cucumber features -n 20") end task :windows_10_chrome_latest do run_tests('Windows 10', 'chrome', 'latest', 'junit_reports/windows_10_chrome_latest') end task :bigsur_chrome_latest do run_tests('BIGSUR', 'chrome', 'latest', 'junit_reports/bigsur_chrome_latest') end multitask :test_testingbot => [ :windows_10_chrome_latest, :bigsur_chrome_latest, ] do puts 'Running automation' end To start the test, please run this command: bundle exec rake test_testingbot ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field, inside the `env.rb` file. capabilities = Selenium::WebDriver::Options.chrome capabilities.browser_version = ENV['version'] capabilities.platform_name = ENV['platform'] tb_options = {} tb_options['selenium-version'] = '3.14.0' capabilities.add_option('tb:options', tb_options) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Capybara test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: **env.rb** : url = "http://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@localhost:4445/wd/hub".strip Capybara::Selenium::Driver.new(app, :browser => :remote, :url => url, :capabilities => capabilities) ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To start running tests in parallel, add more browser configurations in the `Rakefile`: **Rakefile** : def run_tests(platform, browser, version, junit_dir) system("platform=\"#{platform}\" browserName=\"#{browser}\" version=\"#{version}\" JUNIT_DIR=\"#{junit_dir}\" parallel_cucumber features -n 20") end task :windows_10_chrome_latest do run_tests('Windows 10', 'chrome', 'latest', 'junit_reports/windows_10_chrome_latest') end task :bigsur_chrome_latest do run_tests('BIGSUR', 'chrome', 'latest', 'junit_reports/bigsur_chrome_latest') end multitask :test_testingbot => [ :windows_10_chrome_latest, :bigsur_chrome_latest, ] do puts 'Running automation' end Footer The `-n 20` in the example below specifies how many parallel sessions to run. Usually you would use the same number as the maximum parallel sessions allowed by your TestingBot plan. To run your tests in parallel, run this command: bundle exec rake test_testingbot ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/cucumber # Cucumber Automated Testing See our [Cucumber example repository](https://github.com/testingbot/ruby-cucumber-example). To get started, please make sure you have installed the necessary gems: source 'http://rubygems.org' gem 'cucumber' gem 'selenium-webdriver' gem 'rspec' gem 'parallel' ## Example Next, we'll create a `features` and a `steps` file. Combined, they're your test. ### Example feature Feature: Google can search Background: Given I am on Google Scenario: Search for a term When I fill in "q" found by "name" with "TestingBot" And I submit Then I should see title "TestingBot - Google Search" ### Example steps Given /^I am on (.+)$/ do |url| @browser.navigate.to "https://www.google.com" end When /^I fill in "([^"]*)" found by "([^"]*)" with "([^"]*)"$/ do |value, type, keys| @element = @browser.find_element(type, value) @element.send_keys keys end When /^I submit$/ do @element.submit end Then /^I should see title "([^"]*)"$/ do |title| raise "Fail" if @browser.title != title end ### Example env.rb require 'selenium-webdriver' require 'testingbot' Before do capabilities = Selenium::WebDriver::Remote::Capabilities.new capabilities['version'] = ENV['version'] capabilities['browserName'] = ENV['browserName'] capabilities['platform'] = ENV['platform'] url = "https://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@hub.testingbot.com/wd/hub".strip client = Selenium::WebDriver::Remote::Http::Default.new client.open_timeout = 180 @browser = Selenium::WebDriver.for(:remote, :url => url, :options => capabilities, :http_client => client) end After do |test_case| sessionid = @browser.session_id jobname = test_case.name puts "TestingBotSessionId=#{sessionid} job-name=#{jobname}" @browser.quit end Now we can run the test on TestingBot, to start, please run this command: cucumber TB_KEY=api_key TB_SECRET=api_secret SELENIUM_PLATFORM=WINDOWS SELENIUM_BROWSER=chrome ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = Selenium::WebDriver.for :chrome **After:** driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :options => caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :options => caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Ruby WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: ### Example env.rb require 'selenium/webdriver' url = "http://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@localhost:4445/wd/hub" capabilities = Selenium::WebDriver::Remote::Capabilities.new capabilities['platform'] = ENV['SELENIUM_PLATFORM'] || 'ANY' capabilities['name'] = 'My first Test' capabilities['browserName'] = ENV['SELENIUM_BROWSER'] || 'chrome' capabilities['version'] = ENV['SELENIUM_VERSION'] if ENV['SELENIUM_VERSION'] browser = Selenium::WebDriver.for(:remote, :url => url, :options => capabilities) Before do |scenario| @browser = browser end at_exit do browser.quit end ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To start running tests in parallel, first we'll define a `browsers.json` file which contains all the browser combinations: [{ "browser": "firefox", "version": "latest", "platform": "VENTURA" }, { "browser": "chrome", "version": "latest", "platform": "WIN10" }] Now, we'll create a single test ( **features** and **steps** file) which we'll use to run on the browser combinations we defined above. Feature: Google can search Background: Given I am on Google Scenario: Search for a term When I fill in "q" found by "name" with "TestingBot" And I submit Then I should see title "TestingBot - Google Search" Given /^I am on (.+)$/ do |url| @browser.navigate.to "https://www.google.com" end When /^I fill in "([^"]*)" found by "([^"]*)" with "([^"]*)"$/ do |value, type, keys| @element = @browser.find_element(type, value) @element.send_keys keys end When /^I submit$/ do @element.submit end Then /^I should see title "([^"]*)"$/ do |title| raise "Fail" if @browser.title != title end Now we need to create a Ruby script that will run the test above, and use the environment variables to determine browser/OS combination. require 'selenium/webdriver' url = "https://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@hub.testingbot.com/wd/hub" capabilities = Selenium::WebDriver::Remote::Capabilities.new capabilities['platform'] = ENV['SELENIUM_PLATFORM'] capabilities['version'] = ENV['SELENIUM_VERSION'] capabilities['browserName'] = ENV['SELENIUM_BROWSER'] capabilities['build'] = ENV['TB_AUTOMATE_BUILD'] if ENV['TB_AUTOMATE_BUILD'] browser = Selenium::WebDriver.for(:remote, :url => url, :options => capabilities) Before do |scenario| @browser = browser end at_exit do browser.quit end Finally, we create a `Rakefile` which handles the running of the tests in parallel. require 'rubygems' require 'cucumber' require 'cucumber/rake/task' require 'parallel' require 'json' @browsers = JSON.load(open('browsers.json')) @parallel_limit = ENV["nodes"] || 1 @parallel_limit = @parallel_limit.to_i task :cucumber do Parallel.each(@browsers, :in_processes => @parallel_limit) do |browser| begin puts "Running with: #{browser.inspect}" ENV['SELENIUM_BROWSER'] = browser['browserName'] ENV['SELENIUM_VERSION'] = browser['version'] ENV['SELENIUM_PLATFORM'] = browser['platform'] Rake::Task[:run_features].execute() rescue StandardError => e puts "Error while running task: #{e.message}" end end end Cucumber::Rake::Task.new(:run_features) task :default => [:cucumber] To run your tests in parallel, run this command: rake TB_KEY=api_key TB_SECRET=api_secret nodes=3 ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/rspec # RSpec Automated Testing See our [RSpec example repository](https://github.com/testingbot/ruby-rspec-example) for a simple example on how to run RSpec tests in parallel on TestingBot. First, let's create a `testingbot_driver.rb` file which makes it easy to run tests on TestingBot: require "selenium/webdriver" module TestingbotDriver class << self def testingbot_endpoint "https://key:secret@hub.testingbot.com/wd/hub" end def new_driver caps = { platform: "MAC", browserName: "Chrome", version: "latest" } Selenium::WebDriver.for :remote, :url => testingbot_endpoint, :desired_capabilities => caps end end end Now, we need to tell RSpec to use our custom driver to run the test. The best way to do this, is by defining an around hook: **spec\_helper.rb** : require "rspec" require_relative "testingbot_driver" RSpec.configure do |config| config.around(:example) do |example| @driver = TestingbotDriver.new_driver begin example.run ensure @driver.quit end end end Now, let's create an actual test that will use TestingBot: rspec example.rb require_relative "spec_helper" describe "Google's Search Functionality" do it "can find search results" do @driver.manage.timeouts.implicit_wait = 10 @driver.navigate.to "https://www.google.com" raise "Unable to load Google." unless @driver.title.include? "Google" query = @driver.find_element :name, "q" query.send_keys "TestingBot" query.submit puts @driver.title end end ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** driver = Selenium::WebDriver.for :chrome **After:** driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a RSpec test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: **testingbot\_driver.rb** require "selenium/webdriver" module TestingbotDriver class << self def testingbot_endpoint "http://key:secret@localhost:4445/wd/hub" end def new_driver caps = { platform: "CATALINA", browserName: => "Chrome", version: "latest" } Selenium::WebDriver.for :remote, :url => testingbot_endpoint, :desired_capabilities => caps end end end ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Add the parallel\_tests gem to your Gemfile: gem "rspec", "~> 3.0.0" gem "parallel_tests", "~> 1.6.1 Now create some more tests in the same spec directory. Make sure the tests also end with `_spec.rb` in the filename. Once you have some more tests, you can run the tests in parallel with this command: bundle exec parallel_rspec -n 2 spec/ The `-n 2` means how many tests you will run concurrently. This should match up with the number of parallel tests you have with your TestingBot paid plan or 2 for the free trial. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/testunit # Test::Unit Automated Testing See our [TestUnit example repository](https://github.com/testingbot/ruby-testunit-example) for a simple example on how to run TestUnit tests in parallel on TestingBot. ### Example Test::Unit require 'rubygems' require 'selenium-webdriver' require 'test/unit' class SampleTest < Test::Unit::TestCase def setup url = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub" @driver = Selenium::WebDriver.for(:remote, :url => url) end def test_post @driver.navigate.to "https://www.google.com/ncr" element = @driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit assert_equal(@driver.title, "TestingBot - Google Search") end def teardown @driver.quit end end **Before:** driver = Selenium::WebDriver.for :chrome **After:** driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Ruby WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: require 'rubygems' require 'selenium-webdriver' require 'test/unit' class SampleTest < Test::Unit::TestCase def setup url = "http://API_KEY:API_SECRET@localhost:4445/wd/hub" @driver = Selenium::WebDriver.for(:remote, :url => url) end def test_post @driver.navigate.to "https://www.google.com" element = @driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit assert_equal(@driver.title, "TestingBot - Google Search") end def teardown @driver.quit end end ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. The example below demonstrates how you can easily run tests simultaneously in a variety of browsers. First, you need to add the [parallel testing gem](https://github.com/grosser/parallel_tests) to your Gemfile. This Gem will allow you to run multiple tests simultaneously. Create 2 test files: `test_google_ie9.rb` and `test_google_ff.rb` **test\_google\_ie9.rb** require 'rubygems' require 'selenium-webdriver' require 'test/unit' class SampleTest1 < Test::Unit::TestCase def setup key=ENV['TB_KEY'] secret=ENV['TB_SECRET'] url = "https://#{key}:#{secret}@hub.testingbot.com/wd/hub" capabilities = Selenium::WebDriver::Remote::Capabilities.chrome capabilities.platform = :WINDOWS capabilities.browserName = "internet explorer" capabilities.version = 9 @driver = Selenium::WebDriver.for(:remote, :url => url, :desired_capabilities => capabilities) end def test_post @driver.navigate.to "https://www.google.com" element = @driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit assert_equal(@driver.title, "TestingBot - Google Search") end def teardown @driver.quit end end **test\_google\_ff.rb** : require 'rubygems' require 'selenium-webdriver' require 'test/unit' class SampleTest1 < Test::Unit::TestCase def setup key=ENV['TB_KEY'] secret=ENV['TB_SECRET'] url = "https://#{key}:#{secret}@hub.testingbot.com/wd/hub" capabilities = Selenium::WebDriver::Remote::Capabilities.chrome capabilities.platform = :WINDOWS capabilities.browserName = "firefox" capabilities.version = "latest" @driver = Selenium::WebDriver.for(:remote, :url => url, :desired_capabilities => capabilities) end def test_post @driver.navigate.to "https://www.google.com" element = @driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit assert_equal(@driver.title, "TestingBot - Google Search") end def teardown @driver.quit end end Now you need to instruct the parallel\_test gem to run these two tests in parallel: TB_KEY="key" TB_SECRET="secret" parallel_test -n 2 test_google_ie9.rb test_google_ff.rb ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/minitest # Minitest Automated Testing Minitest is a very fast unit testing framework which supports TDD, BDD, mocking and benchmarking. To begin, please make sure you have Minitest installed on your system: gem install minitest ## Example code require 'minitest/autorun' require 'selenium-webdriver' class GoogleTest < Minitest::Test def setup options = Selenium::WebDriver::Chrome::Options.new options.browser_version = 'latest' options.platform_name = 'WIN10' options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'Minitest Example' }) @driver = Selenium::WebDriver.for(:remote, url: 'https://hub.testingbot.com/wd/hub', options: options ) end def test_google_search @driver.navigate.to 'https://www.google.com' element = @driver.find_element(:name, 'q') element.send_keys 'TestingBot' element.submit assert_includes @driver.title, 'TestingBot' end def teardown @driver.quit end end ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. driver = Selenium::WebDriver.for(:remote, url: 'https://hub.testingbot.com/wd/hub', options: options ) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Ruby WebDriver test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: require 'minitest/autorun' require 'selenium-webdriver' class GoogleTest < Minitest::Test def setup options = Selenium::WebDriver::Chrome::Options.new options.browser_version = 'latest' options.platform_name = 'WIN10' options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'Minitest Tunnel Example' }) @driver = Selenium::WebDriver.for(:remote, url: 'http://localhost:4445/wd/hub', options: options ) end def test_google_search @driver.navigate.to 'https://www.google.com' element = @driver.find_element(:name, 'q') element.send_keys 'TestingBot' element.submit assert_includes @driver.title, 'TestingBot' end def teardown @driver.quit end end ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. The example below demonstrates how you can easily run tests simultaneously in a variety of browsers. Create a `browsers.json` file with the [list of browsers](https://testingbot.com/support/web-automate/browsers) you want to use to run tests in parallel: [ { "browserName": "firefox", "browserVersion": "latest", "platformName": "WIN10" }, { "browserName": "safari", "browserVersion": "18", "platformName": "SEQUOIA" }, { "browserName": "chrome", "browserVersion": "latest", "platformName": "WIN11" } ] Now we need to create the test and use environment variables which we will pass to the test script. require 'minitest/autorun' require 'selenium-webdriver' class GoogleTest < Minitest::Test def setup # Dynamically select browser options based on environment options_class = case ENV['TB_BROWSERNAME'] when 'firefox' then Selenium::WebDriver::Firefox::Options when 'safari' then Selenium::WebDriver::Safari::Options else Selenium::WebDriver::Chrome::Options end options = options_class.new options.browser_version = ENV['TB_VERSION'] options.platform_name = ENV['TB_PLATFORM'] options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'Parallel Test' }) @driver = Selenium::WebDriver.for(:remote, url: 'https://hub.testingbot.com/wd/hub', options: options ) end def test_google_search @driver.navigate.to 'https://www.google.com' element = @driver.find_element(:name, 'q') element.send_keys 'TestingBot' element.submit assert_includes @driver.title, 'TestingBot' end def teardown @driver.quit end end Now we need to create a `Rakefile` which will start the tests in parallel. require 'rake/testtask' require 'parallel' require 'json' @browsers = JSON.load(File.open('browsers.json')) @test_folder = 'test/*_test.rb' @parallel_limit = (ENV['nodes'] || 1).to_i task :minitest do current_browser = '' begin Parallel.map(@browsers, in_threads: @parallel_limit) do |browser| current_browser = browser puts "Running Browser: #{browser.inspect}" ENV['TB_BROWSERNAME'] = browser['browserName'] ENV['TB_VERSION'] = browser['browserVersion'] ENV['TB_PLATFORM'] = browser['platformName'] Dir.glob(@test_folder).each do |test_file| IO.popen("ruby #{test_file}") do |io| io.each { |line| puts line } end end end rescue SystemExit, Interrupt puts 'User stopped script!' puts "Failed to run tests for #{current_browser.inspect}" end end task default: [:minitest] ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ruby/watir # Watir WebDriver Automated Testing See our [Watir example repository](https://github.com/testingbot/ruby-rspec-watir-example) for a simple example on how to run Watir tests in parallel on TestingBot. Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. To install the watir-webdriver gem: gem install watir-webdriver ### Example with Watir WebDriver require "watir-webdriver" caps = WebDriver::Remote::Capabilities.new caps[:browserName] = "chrome" caps[:version] = "latest-1" caps[:platform] = :WINDOWS caps[:name] = "Watir WebDriver Test" browser = Watir::Browser.new( :remote, :url => "http://key:secret@hub.testingbot.com/wd/hub", :desired_capabilities => caps) browser.goto "https://www.google.com/ncr" browser.text_field(:name => 'q').set 'TestingBot' browser.button(:name => 'btnG').click puts browser.title browser.quit ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** browser = Watir::Browser.new(:firefox) **After:** browser = Watir::Browser.new(:remote, :url => "http://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. browser = Watir::Browser.new(:remote, :url => "http://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Watir test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: require "watir-webdriver" caps = WebDriver::Remote::Capabilities.new caps[:browserName] = "firefox" caps[:version] = "latest-1" caps[:platform] = :WINDOWS caps[:name] = "Watir WebDriver Test" browser = Watir::Browser.new( :remote, :url => "http://key:secret@localhost:4445/wd/hub", :desired_capabilities => caps) browser.goto "https://www.google.com/ncr" browser.text_field(:name => 'q').set 'TestingBot' browser.button(:name => 'btnG').click puts browser.title browser.quit ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. You can use our [Ruby API client](https://github.com/testingbot/testingbot_ruby) to report back test results. api = TestingBot::Api.new(key, secret) api.update_test(driver.session_id, { :name => new_name, :success => true }) ## Other Ruby Framework examples - [Capybara](https://testingbot.com/support/web-automate/selenium/ruby/capybara) Capybara is an integration testing tool for rack based web applications. - [Cucumber](https://testingbot.com/support/web-automate/selenium/ruby/cucumber) Cucumber is a Ruby based test tool for BDD. - [RSpec](https://testingbot.com/support/web-automate/selenium/ruby/rspec) RSpec is a behavior-driven development (BDD) framework, inspired by JBehave. - [Test::Unit](https://testingbot.com/support/web-automate/selenium/ruby/testunit) Test-Unit is a xUnit family unit testing framework for Ruby. - [Minitest](https://testingbot.com/support/web-automate/selenium/ruby/minitest) Minimal (mostly drop-in) replacement for test-unit. - [Watir](https://testingbot.com/support/web-automate/selenium/ruby/watir) Watir, pronounced water, is an open-source (BSD) family of Ruby libraries for automating web browsers. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/robotframework # Robot Framework Automated WebDriver Testing See our [RobotFramework example repository](https://github.com/testingbot/robotframework-web-example) for a first example on how to run RobotFramework tests on TestingBot. With [SeleniumLibrary](https://github.com/robotframework/SeleniumLibrary) you can run WebDriver tests with [Robot Framework](https://robotframework.org/). Robot Framework is a test automation framework to run acceptance tests. The Robot test framework allows you to build easy to read test cases, using keyword driven and behavior-driven approaches. The framework provides reports, in HTML format. ## Setting up Robot Framework Make sure you've installed [pip](https://pip.pypa.io/en/stable/), then to install the necessary libs: pip install robotframework-seleniumlibrary requests ### Running your first test Below is an example on how to run a simple test on Firefox. When the test has finished, the test name and success state is sent to TestingBot so you can see the test success/failures in our dashboard. Save the example below in a `test.robot` file: [Browser Options](https://testingbot.com#)[Desired Capabilities](https://testingbot.com#) ***Settings*** Library SeleniumLibrary Library TestingBot Test Setup Open test browser Test Teardown Close test browser ***Variables*** ${CREDENTIALS} key:secret ***Test Cases*** Simple Test Go to https://www.google.com Page should contain Google ***Keywords*** Open test browser Open browser about: firefox ... remote_url=http://${CREDENTIALS}@hub.testingbot.com/wd/hub ... desired_capabilities=browserName:${BROWSER},version:${VERSION},platform:${PLATFORM} Close test browser ... Report TestingBot status ... ${SUITE_NAME} | ${TEST_NAME} ... ${TEST_STATUS} ${CREDENTIALS} Close all browsers Save the code below in a `TestingBot.py` file: import requests from robot.libraries.BuiltIn import BuiltIn def report_testingbot_status(name, status, credentials): selenium = BuiltIn().get_library_instance('SeleniumLibrary') session_id = selenium.driver.session_id payload = {'test[name]': name, 'test[success]': int(status == 'PASS')} key, secret = credentials.split(':') url = 'https://api.testingbot.com/v1/tests/{0}'.format(session_id) response = requests.put(url, data=payload, auth=(key, secret)) assert response.status_code == 200, response.text To run the test, run this command: PYTHONPATH=$PYTHONPATH:. robot --variable BROWSER:chrome --variable VERSION:latest --variable PLATFORM:MAC test.robot Once the test finished running, you should see it in the [member dashboard](https://testingbot.com/members). Use the variables to run the test on different platforms/browsers/versions. ***Settings*** Library SeleniumLibrary Library TestingBot Library BrowserOptions Test Setup Open test browser Test Teardown Close test browser ***Test Cases*** Simple Test Go to https://www.google.com Page should contain Google ***Keywords*** Open test browser ${options}= Get Browser Options ${BROWSER} # Set capabilities Call Method ${options} set_capability platformName ${PLATFORM} Call Method ${options} set_capability browserName ${BROWSER} Call Method ${options} set_capability browserVersion ${VERSION} # Set custom TestingBot capabilities using tb:options ${tb_options}= Create Dictionary name=test build=MyTestBuild Call Method ${options} set_capability tb:options ${tb_options} # Open browser with options Open Browser remote_url=https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub options=${options} Close test browser ... Report TestingBot status ... ${SUITE_NAME} | ${TEST_NAME} ... ${TEST_STATUS} ${TB_KEY}:${TB_SECRET} Close all browsers Save the code below in a `TestingBot.py` file: import requests from robot.libraries.BuiltIn import BuiltIn def report_testingbot_status(name, status, credentials): selenium = BuiltIn().get_library_instance('SeleniumLibrary') session_id = selenium.driver.session_id payload = {'test[name]': name, 'test[success]': int(status == 'PASS')} key, secret = credentials.split(':') url = 'https://api.testingbot.com/v1/tests/{0}'.format(session_id) response = requests.put(url, data=payload, auth=(key, secret)) assert response.status_code == 200, response.text Now we'll need to specify the multiple browser options in a file called `BrowserOptions.py`: from selenium.webdriver import ChromeOptions, FirefoxOptions, EdgeOptions, SafariOptions def get_browser_options(browser): if browser.lower() == 'chrome': return ChromeOptions() elif browser.lower() == 'firefox': return FirefoxOptions() elif browser.lower() == 'edge': return EdgeOptions() elif browser.lower() == 'safari': return SafariOptions() else: raise ValueError(f"Unsupported browser: {browser}") To run the test, run this command: PYTHONPATH=$PYTHONPATH:. robot --variable BROWSER:chrome --variable VERSION:latest --variable PLATFORM:MAC --variable TB_KEY: --variable TB_SECRET: test.robot Once the test finished running, you should see it in the [member dashboard](https://testingbot.com/members). Use the variables to run the test on different platforms/browsers/versions. ### Specifying the operating system, browser and version To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. desired_capabilities=browserName:${BROWSER},browserVersion:${VERSION},platform:${PLATFORM} To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Parallel Testing You can run multiple Robot Framework tests in parallel by using the [Pabot](https://pabot.org/) library. First install Pabot using pip: pip install -U robotframework-pabot Then run your tests using the `pabot` command instead of `robot`: PYTHONPATH=. pabot --processes 2 --loglevel TRACE --variable BROWSER:chrome --variable VERSION:latest --variable PLATFORM:WIN11 --variable TB_KEY:... --variable TB_SECRET:... test.robot Some recommendations when running tests in parallel: - Make sure each test case is independent and does not rely on shared state. - Specify the `--processes` with the same amount as your TestingBot plan allows (parallel test sessions). - Consider using `--processtimeout` to set a timeout for each process. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs ### NodeJS Examples: - [WebdriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) - [TestCafe](https://testingbot.com/support/web-automate/selenium/nodejs/testcafe) - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) # NodeJS Automated Testing First, make sure you have installed NodeJS. If you haven't, you can easily install it by downloading NodeJS from [the NodeJS website](https://nodejs.org/). ## Getting started With TestingBot you can easily run your automated tests with [any NodeJS test framework](https://testingbot.com#frameworks), here's a simple example with **selenium-webdriver** : npm install selenium-webdriver const webdriver = require('selenium-webdriver'); const TB_KEY = process.env.TB_KEY || 'your_key'; const TB_SECRET = process.env.TB_SECRET || 'your_secret'; const capabilities = { 'platformName' : 'WIN10', 'browserName' : 'chrome', 'browserVersion' : 'latest', 'tb:options': { 'name': 'NodeJS Sample Test' } }; async function runTest () { const driver = await new webdriver.Builder() .usingServer(`https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub`) .withCapabilities(capabilities) .build(); await driver.get("https://testingbot.com"); await driver.wait(webdriver.until.titleMatches(/TestingBot/i), 5000); await driver.quit(); } runTest(); This test will start a Chrome browser on Windows in our cloud, go to TestingBot, and verify the page title contains "TestingBot". Your test results are now available on the commandline interface, and in our member area. Make sure to always stop your test (`driver.quit()`), otherwise it will continue running, leading to a timeout. ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** const driver = new webdriver.Builder() .usingServer('http://localhost:4444/wd/hub') .withCapabilities({ 'browserName': 'firefox' }).build(); **After:** const TB_KEY = process.env.TB_KEY || 'your_key'; const TB_SECRET = process.env.TB_SECRET || 'your_secret'; const driver = new webdriver.Builder() .usingServer(`https://${TB_KEY}:${TB_SECRET}@hub.testingbot.com/wd/hub`) .withCapabilities({ 'browserName': 'firefox', 'browserVersion': 'latest', 'platformName': 'WIN10', 'tb:options': { 'name': 'My Test' } }).build(); ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Looking to generate more custom capabilities? Use the [Selenium capabilities generator](https://testingbot.com/support/web-automate/selenium/capabilities). ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a NodeJS test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: const webdriver = require('selenium-webdriver'); const TB_KEY = process.env.TB_KEY || 'your_key'; const TB_SECRET = process.env.TB_SECRET || 'your_secret'; const capabilities = { 'platformName' : 'WIN10', 'browserName' : 'chrome', 'browserVersion' : 'latest', 'tb:options': { 'name': 'NodeJS Sample Test' } }; async function runTest () { const driver = await new webdriver.Builder() .usingServer(`http://${TB_KEY}:${TB_SECRET}@localhost:4445/wd/hub`) .withCapabilities(capabilities) .build(); await driver.get("https://testingbot.com"); await driver.wait(webdriver.until.titleMatches(/TestingBot/i), 5000); await driver.quit(); } runTest(); ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using a test runner like [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) to run your tests simultaneously. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. Install our NPM package to interact with the TestingBot API: npm install testingbot-api After your test completed, you can send back the test success state and other meta-data: const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: "api_key", api_secret: "api_secret" }); tb.updateTest({ 'test[name]' : 'Example Test', 'test[success]' : true }, sessionId, done); To retrieve the `sessionId` of the test, please see [Get Session ID](https://testingbot.com/support/web-automate/selenium/get-session-id?type=nodejs). ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Testplane (Hermione)](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Testplane (formerly Hermione) is a test framework similar to WebDriverIO, with automatic test retries and plugins. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch # Nightwatch Automated Browser Testing See the TestingBot [NightWatch example repository](https://github.com/testingbot/nightwatch-example) for an example on how to run NightWatch tests in parallel on TestingBot. Install Nightwatch: npm install nightwatch testingbot-api --save-dev Now, you'll need to create a settings file so that Nightwatch knows it needs to connect to the TestingBot Selenium Grid. Create a `nightwatch.conf.js` file with the following contents. const testingBotOptions = { 'tb:options' : { "build" : "nightwatch-example", "name" : "Nightwatch Example Test", "seleniumVersion" : "4.24.0", key: '${TESTINGBOT_KEY}' || 'YOUR_KEY', secret: '${TESTINGBOT_SECRET}' || 'YOUR_SECRET', }, } const testingBot = { webdriver: { start_process: false, timeout_options: { timeout: 120000, retry_attempts: 3 }, keep_alive: true }, selenium: { host: 'hub.testingbot.com', port: 443 }, desiredCapabilities: { browserName: 'chrome', ...testingBotOptions } } const nightwatchConfigs = { src_folders: ['tests'], custom_commands_path: 'custom_commands', output_folder: 'reports', live_output: true, test_settings: { default: { launch_url: 'https://testingbot.com' }, "testingbot.chrome": { ...testingBot, desiredCapabilities:{ browserName: 'chrome', ...testingBotOptions } }, "testingbot.firefox": { ...testingBot, desiredCapabilities:{ browserName: 'firefox', ...testingBotOptions } }, "testingbot.edge": { ...testingBot, desiredCapabilities:{ browserName: 'edge', ...testingBotOptions } } } } module.exports = nightwatchConfigs; We will also need to add a test script, let's create a new directory called `tests` and add a file: `googleTest.js` const https = require('https'); module.exports = { '@tags': ['test'], 'Google': function(client) { client .url('https://testingbot.com') .waitForElementVisible('body', 1000) .assert.textContains('body', 'TestingBot') .end(); }, afterEach: function(client, done) { client.customTestingBotEnd(); done(); } }; To report back the status to TestingBot, we'll need to create a custom command in the `custom_commands` directory. Please create a file called `customTestingBotEnd.js` in this directory. exports.command = function(callback) { const TestingBot = require("testingbot-api"); const tb = new TestingBot({ api_key: process.env.TESTINGBOT_KEY, api_secret: process.env.TESTINGBOT_SECRET }); const sessionid = this.capabilities['webdriver.remote.sessionid'], jobName = this.currentTest.name, passed = this.currentTest.results.testcases[jobName].failed === 0; console.log("TestingBotSessionId=" + sessionid); tb.updateTest({ 'test[success]': passed, 'test[name]': jobName }, sessionid, () => { this.end(callback) }); }; To run the test, please run this command: TESTINGBOT_KEY=... TESTINGBOT_SECRET=... ./node_modules/.bin/nightwatch --test ./tests/googleTest.js --env testingbot.chrome ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** "selenium" : { "start_process" : false, "host" : "localhost", "port" : 4444 }, **After:** "selenium" : { "start_process" : false, "host" : "hub.testingbot.com", "port" : 443 }, ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Looking to generate more custom capabilities? Use the [Selenium capabilities generator](https://testingbot.com/support/web-automate/selenium/capabilities). ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a NodeJS test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: { "src_folders" : ["tests/"], "selenium" : { "start_process" : false, "host" : "localhost", "port" : 4445 }, "test_settings" : { "default" : { "desiredCapabilities": { "browserName": "firefox", "platformName": "WIN10", "browserVersion": "latest" } } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, you can use the following command to specify multiple capabilities at once. ./node_modules/.bin/nightwatch --test ./tests/googleTest.js --env testingbot.chrome,testingbot.edge,testingbot.firefox ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. Install our NPM package to interact with the TestingBot API: npm install testingbot-api After your test completed, you can send back the test success state and other meta-data: exports.command = function(callback) { const TestingBot = require("testingbot-api"); const tb = new TestingBot({ api_key: process.env.TB_KEY, api_secret: process.env.TB_SECRET }); const sessionid = this.capabilities['webdriver.remote.sessionid'], jobName = this.currentTest.name, passed = this.currentTest.results.testcases[jobName].failed === 0; console.log("TestingBotSessionId=" + sessionid); tb.updateTest({ 'test[success]': passed, 'test[name]': jobName }, sessionid, () => { this.end(callback) }); }; ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/protractor # Protractor Automated Browser Testing Install Protractor: npm install -g protractor Now, you'll need to create a config file so that Protractor knows it needs to connect to our Selenium Grid. Create a file called `conf.js`: exports.config = { seleniumAddress: 'https://hub.testingbot.com/wd/hub', specs: ['spec.js'], maxSessions: 6, // 6 TOTAL sessions across all capabilities multiCapabilities: [{ // in 1 chrome run the 10 specs sequentially browserName: 'chrome', platform: 'WIN10', version: 'latest', name: 'My First Protractor test', client_key: "api_key", client_secret: "api_secret" }, { // 5 chrome sessions will start, each running 1 spec file at a time, until all 10 finish browserName: 'chrome', platform: 'BIGSUR', version: 'latest-1', name: 'My First Protractor test', shardTestFiles: true, maxInstances: 5, client_key: "api_key", client_secret: "api_secret" }, { // Same as repeating the previous setup twice browserName: 'chrome', platform: 'WIN10', version: 'latest-2', name: 'My First Protractor test', shardTestFiles: true, maxInstances: 5, count: 2, client_key: "api_key", client_secret: "api_secret" }] } Next, we'll create a `spec.js` (which we defined above in the conf file). This will contain the test logic. describe('Protractor Demo App', function() { it('should have a title', function() { browser.get('http://juliemr.github.io/protractor-demo/'); expect(browser.getTitle()).toEqual('Super Calculator'); }); }); To run the test, please run this command: protractor conf.js ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** exports.config = { multiCapabilities: [{ browserName: 'chrome' }] } **After:** exports.config = { seleniumAddress: 'https://hub.testingbot.com/wd/hub', multiCapabilities: [{ browserName: 'chrome', client_key: "api_key", client_secret: "api_secret" }] } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Protractor test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: exports.config = { seleniumAddress: 'http://localhost:4445/wd/hub', specs: ['spec.js'], multiCapabilities: [{ browserName: 'chrome', client_key: "api_key", client_secret: "api_secret" }] } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, please see the following example: exports.config = { capabilities: { browserName: 'chrome', count: 2 // number of parallel tests } } ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. exports.config = { seleniumAddress: 'https://hub.testingbot.com/wd/hub', specs: ['spec.js'], maxSessions: 6, // 6 TOTAL sessions across all capabilities multiCapabilities: [{ // in 1 chrome run the 10 specs sequentially browserName: 'chrome', platform: 'WIN10', version: 'latest', name: 'My First Protractor test', client_key: "api_key", client_secret: "api_secret" }, { // 5 chrome sessions will start, each running 1 spec file at a time, until all 10 finish browserName: 'chrome', platform: 'BIGSUR', version: 'latest-1', name: 'My First Protractor test', shardTestFiles: true, maxInstances: 5, client_key: "api_key", client_secret: "api_secret" }, { // Same as repeating the previous setup twice browserName: 'chrome', platform: 'WIN10', version: 'latest-2', name: 'My First Protractor test', shardTestFiles: true, maxInstances: 5, count: 2, client_key: "api_key", client_secret: "api_secret" }], onComplete: function (passed) { browser.executeScript("tb:test-result=" + (passed ? "passed" : "failed")); } } Please see the example below, where we use the `onComplete` callback provided by Protractor. onComplete: function (passed) { browser.executeScript("tb:test-result=" + (passed ? "passed" : "failed")); } This `onComplete` handler will be invoked after every Protractor test. The test status will be sent to TestingBot, where we will display the pass/fail state in your test dashboard. ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/hermione # Hermione Testing **Note:** Hermione has been renamed to [Testplane](https://github.com/gemini-testing/testplane). The examples below still work, but you may want to migrate to Testplane for future development. Hermione is a test framework inspired upon WebDriverIO. If you are already familiar with WebDriverIO and Mocha, you will enjoy working with the Hermione Test Framework. There are several advantages that Hermione has over WebDriverIO: - **Runs tests in subprocesses** : to take advantage of all your CPU cores. - **Extensible** : You can add custom commands in the hermione config and use them as `browser.myCustomCommand` in tests. - **Built-in assert library** : Hermione provides a global `expect` variable that gives you access to a number of matchers that let you validate different things on the browser, an element or mock object. - **Retry failed tests** : To prevent flaky tests, hermione retries a failed test before marking it as failed. ## Setting up Hermione To set up Hermione, you can enter the following command in your terminal. First, make sure you've created a directory where you will set up a new Hermione project. npm init hermione-app . You will be asked a couple of questions, which will help Hermione to decide how to configure your configuration file (`.hermione.conf.js`). Once the configuration file has been created, you'll need to edit the browsers block and add your TestingBot key and secret. Here's an example of what it should look like: module.exports = { gridUrl: 'https://hub.testingbot.com/wd/hub', baseUrl: 'http://localhost', pageLoadTimeout: 0, httpTimeout: 60000, testTimeout: 90000, resetCursor: false, sets: { desktop: { files: [ 'tests/**/*.hermione.js' ], browsers: [ 'chrome' ] } }, browsers: { chrome: { automationProtocol: 'webdriver', // default value desiredCapabilities: { browserName: 'chrome', key: process.env.TB_KEY, // or replace with your TestingBot Key secret: process.env.TB_SECRET // or replace with your TestingBot Secret } } }, plugins: { 'html-reporter/hermione': { // https://github.com/gemini-testing/html-reporter enabled: true, path: 'hermione-report', defaultView: 'all', diffMode: '3-up-scaled' } } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Hermione test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: module.exports = { gridUrl: 'http://localhost:4445/wd/hub', baseUrl: 'http://localhost', ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. By default, Hermione will run all tests simultaneously. We advise to set the `parallelLimit` option to the same number of parallel tests as your TestingBot plan allows. This will prevent tests from queueing up and eventually timing out. module.exports = { parallelLimit: 2 // depends on the TestingBot plan you have } ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. In your tests, you can mark the current test as passed or failed, by using the `executeScript` command: browser.executeScript("tb:test-result=" + (passed ? "passed" : "failed")); ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs # Getting started with CodeceptJS [CodeceptJS](https://codecept.io/) is an end-to-end testing framework which supports Selenium, Appium, Playwright, Puppeteer and more. It offers scenario driven testing, PageObjects support, beautiful reports and much more. Let's start with installing everything we need: npm i --save-dev codeceptjs @wdio/testingbot-service Now we need to set up CodeceptJS. Please use the command below to initialize a new project: npx codeceptjs init This will ask a bunch of questions, and will create a sample test at the end of the process. ## Example test Now that you have everything set up, you can create a very simple test: Feature('My First Test'); Scenario('test something', ({ I }) => { I.amOnPage('https://testingbot.com'); I.see('TestingBot'); }); This simple test will navigate to TestingBot and verify if the name TestingBot is present on the page. Before we can run this test, we need to configure CodeceptJS to connect and run a browser on our grid. ## Configuration You can configure CodeceptJS with a `codecept.conf.js` file: const { setHeadlessWhen } = require('@codeceptjs/configure'); // turn on headless mode when running with HEADLESS=true environment variable // HEADLESS=true npx codecept run setHeadlessWhen(process.env.HEADLESS); exports.config = { tests: './*_test.js', output: './output', helpers: { WebDriver : { url: "hub.testingbot.com", browser: 'chrome', desiredCapabilities: { build: "CodeceptJS", platform: 'Windows 10', browserName: 'chrome', version: 'latest' }, smartWait: 5000, restart: false, timeouts: { "script": 60000, "page load": 10000 } } }, include: { I: './steps_file.js' }, bootstrap: null, mocha: {}, name: 'codeceptjs-example', plugins: { retryFailedStep: { enabled: true }, screenshotOnFail: { enabled: true }, wdio: { enabled: true, services: ['testingbot'], user: 'YOUR KEY HERE', key: 'YOUR SECRET HERE' } } } To run the test, you can do: npx codeceptjs run --steps This will start the latest Chrome browser on TestingBot and run the test on our grid. You will see a test appear in your member dashboard on TestingBot, together with a video, log files and other assets generated by the test. ## Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before** // codecept.conf.js exports.config = { tests: './*_test.js', output: './output', helpers: { WebDriver : {} } }; **After** // codecept.conf.js plugins: { ... wdio: { enabled: true, services: ['testingbot'], user: 'YOUR KEY HERE', key: 'YOUR SECRET HERE' } } ### Specifying the operating system, browser and version To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Reporting Test Results If you are using the [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) then your tests will automatically report back meta-data to TestingBot (like test success, name, stacktrace, ...) ## Testing Internal/Staged Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a WebdriverIO test with our Tunnel: 1. Adjust your `codecept.conf.js` configuration to use `tbTunnel: true`. The [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) will automatically download and use the tunnel for your tests. **codecept.conf.js** plugins: { ... wdio: { enabled: true, services: ['testingbot'], user: 'YOUR KEY HERE', key: 'YOUR SECRET HERE', tbTunnel: true } } ## Parallel Testing Please see [CodeceptJS parallel testing](https://codecept.io/parallel/#parallel-execution-by-workers) on how to run your tests in parallel. You can specify the concurrency by specifying a number of workers: npx codeceptjs run-workers 2 or run multiple different browsers with: npx codeceptjs run-multiple --all ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Other Options We offer many other [test options](https://testingbot.com/support/web-automate/selenium/test-options), for example: disable video recording, specifying a custom Firefox Profile, loading Chrome/Firefox/Safari extensions, running an executable before your test starts, uploading files, ... See our [list of test options](https://testingbot.com/support/web-automate/selenium/test-options) for a full list of options to customize your tests. ## Pick a NodeJS test framework - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/soda # NodeJS with Soda Install the TestingBot plugin: npm install testingbot You can now run your Selenium tests with NodeJS on our grid. Run this example: node example.js var soda = require('testingbot') , assert = require('assert'); var browser = soda.createTestingBotClient({ 'url': 'https://www.google.com', 'os': 'Windows', 'browser': 'iexplore', 'browser-version': '8', 'max-duration': 300 }); // Log commands as they are fired browser.on('command', function(cmd, args){ console.log(' \x1b[33m%s\x1b[0m: %s', cmd, args.join(', ')); }); browser .chain .session() .setTimeout(8000) .open('/') .waitForPageToLoad(5000) .getTitle(function(title){ assert.ok(title.indexOf('Google')) }) .testComplete() .end(function(err) { if (err) { console.log(err); } }) ### Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before:** var driver = new webdriver.Builder().usingServer('http://localhost:4444/wd/hub').withCapabilities({ 'browserName' : 'firefox' }).build() **After:** var driver = new webdriver.Builder().usingServer('https://hub.testingbot.com/wd/hub').withCapabilities({ 'browserName' : 'firefox' }).build() ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a NodeJS test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: var wd = require('wd'), testingbotKey = "api_key", testingbotSecret = "api_secret" desiredCaps = { 'browserName': 'firefox', 'platform': 'WIN10', 'version': 'latest', 'client_key': testingbotKey, 'client_secret': testingbotSecret } driver = wd.remote("https://" + testingbotKey + ":" + testingbotSecret + "@" + "localhost:4445/wd/hub") driver.init(desiredCaps, function() { driver.get('https://www.google.com', function() { driver.title(function(err, title) { console.log(title) driver.quit() }) }) }) ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run tests in parallel, we recommend using a test runner like [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) to run your tests simultaneously. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. Install our NPM package to interact with the TestingBot API: npm install testingbot-api After your test completed, you can send back the test success state and other meta-data: const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: "api_key", api_secret: "api_secret" }); tb.updateTest({ 'test[name]' : 'Example Test', 'test[success]' : true }, browser.sessionId, done); ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/wd # NodeJS Automated Testing with WD.js WD.js is a NodeJS client for WebDriver/Selenium. Let's start with making sure WD.js is installed: npm install wd You are now ready to run a WebDriver test with NodeJS on our grid. Please take a look at the following example, this only demonstrates webdriver.io without any test frameworks: describe("using promises and chai-as-promised", function() { let browser; before(function() { browser = wd.remote(url.parse('http://api_key:api_secret@hub.testingbot.com/wd/hub')); ... return browser.init({browserName:'chrome'}); }); beforeEach(function() { return browser.get("http://admc.io/wd/test-pages/guinea-pig.html"); }); after(function() { return browser.quit(); }); it("should retrieve the page title", function() { return browser.title().should.become("WD Tests"); }); it("submit element should be clicked", function() { return browser.elementById("submit").click().eval("window.location.href") .should.eventually.include("&submit"); }); }); ## Configuring capabilities To run your existing tests on TestingBot, your tests will need to be configured to use the TestingBot remote machines. If the test was running on your local machine or network, you can simply change your existing test like this: **Before** browser .init({browserName:'chrome'}) **After** browser = wd.remote(url.parse('http://api_key:api_secret@hub.testingbot.com/wd/hub')); browser .init({browserName:'chrome'}) ### Specifying the operating system, browser and version To let TestingBot know on which browser/platform you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Other Options We offer many other [test options](https://testingbot.com/support/web-automate/selenium/test-options), for example: disable video recording, specifying a custom Firefox Profile, loading Chrome/Firefox/Safari extensions, running an executable before your test starts, uploading files, ... See our [list of test options](https://testingbot.com/support/web-automate/selenium/test-options) for a full list of options to customize your tests. ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio ### WebDriverIO Examples: - [Cucumber](https://testingbot.com#cucumber) - [Mocha](https://testingbot.com#mocha) - [Jasmine](https://testingbot.com#jasmine) # NodeJS Automated Testing with WebdriverIO With WebDriverIO you can run [Mocha](https://testingbot.com#mocha), [Jasmine](https://testingbot.com#jasmine) (v2.0) and [Cucumber](https://testingbot.com#cucumber) tests. See our [WebdriverIO examples repository](https://github.com/testingbot/webdriverio-examples) for some examples on how to use WebdriverIO with TestingBot. TestingBot has its own [WebDriverIO service](https://webdriver.io/docs/testingbot-service.html) plugin which makes configuring your tests easier and which sends test meta-data back to TestingBot. Let's start with making sure `webdriverio` is installed: npm i --save-dev @wdio/cli @wdio/local-runner ## WebDriverIO TestingBot Service WebDriverIO contains a [TestingBot service](https://webdriver.io/docs/testingbot-service.html) which makes it easy to run tests with WebDriver.io on TestingBot. With this service, WebDriverIO will start a [TestingBot Tunnel](https://testingbot.com/support/tunnel) if required, and send back test meta-data (passed state, name, build-id, ...) In order to use the service you need to install it: npm install @wdio/testingbot-service --save-dev ## Cucumber Example To run Cucumber tests on TestingBot, please follow these steps: npm install @wdio/testingbot-service --save-dev npm install @wdio/dot-reporter --save-dev npm install @wdio/cucumber-framework --save-dev Now we'll make a simple Cucumber test which uses Firefox on TestingBot to go to Google.com and verify the page's title. Please create the following files: **wdio.conf.js** exports.config = { /** * specify test files */ specs: [ './features/*.feature' ], /** * capabilities */ capabilities: [{ browserName: 'chrome', browserVersion: 'latest', platformName: 'WIN10' }], /** * test configurations */ logLevel: 'silent', coloredLogs: true, screenshotPath: 'screenshots', waitforTimeout: 10000, connectionRetryTimeout: 480000, framework: 'cucumber', services: [ ['testingbot'] ], user: 'api_key', key: 'api_secret', reporters: ['dot'], reporterOptions: { outputDir: './' }, cucumberOpts: { require: ['./step-definitions.js'] } }; **step-definitions.js** const { Given, When, Then } = require('@cucumber/cucumber') const assert = require('assert') Given('I go on the website {string}', async (url) => { await browser.url(url) }) Then('should the title of the page be {string}', async (expectedTitle) => { assert.equal(await browser.getTitle(), expectedTitle) }) **features/my-feature.feature** Feature: Example feature As a user of Google I should be able to go to Google and see its correct title Scenario: Get title of website Given I go on the website "https://www.google.com/" Then should the title of the page be "Google" Now we can run this test on TestingBot! To start the test, please run this command: ~/node_modules/.bin/wdio run wdio.conf.js The test will now run on TestingBot. At the end of the test, the testname and success state will be available on TestingBot, together with a video and other meta-data. ## Mocha Example To run Mocha tests on TestingBot, please follow these steps: npm install @wdio/testingbot-service --save-dev npm install @wdio/dot-reporter --save-dev npm install @wdio/mocha-framework --save-dev Now we'll make a simple Mocha test which uses Firefox on TestingBot to go to Google.com and verify the page's title. Please create the following files: **wdio.conf.js** exports.config = { /** * specify test files */ specs: [ './runner-specs/mocha.test.js' ], /** * capabilities */ capabilities: [{ browserName: 'chrome', browserVersion: 'latest', platformName: 'WIN10' }], /** * test configurations */ logLevel: 'silent', coloredLogs: true, screenshotPath: 'screenshots', waitforTimeout: 10000, connectionRetryTimeout: 480000, framework: 'mocha', services: [ ['testingbot'] ], user: 'api_key', key: 'api_secret', reporters: ['dot'], reporterOptions: { outputDir: './' }, mochaOpts: { ui: 'bdd' } }; **runner-specs/mocha.test.js** const assert = require('assert'); describe('google page', async function() { it('should have the right title', async function () { await browser.url('https://www.google.com'); const title = await browser.getTitle(); assert.equal(title, 'Google'); }); }); Now we can run this test on TestingBot. To start the test, please run this command: ~/node_modules/.bin/wdio run wdio.conf.js The test will now run on TestingBot. At the end of the test, the testname and success state will be available on TestingBot, together with a video and other meta-data. ## Jasmine Example To run Jasmine tests on TestingBot, please follow these steps: npm install @wdio/testingbot-service --save-dev npm install @wdio/dot-reporter --save-dev npm install @wdio/jasmine-framework --save-dev Now we'll make a simple Jasmine test which uses Firefox on TestingBot to go to Google.com and verify the page's title. Please create the following files: **wdio.conf.js** exports.config = { /** * specify test files */ specs: [ './runner-specs/jasmine.spec.js' ], /** * capabilities */ capabilities: [{ browserName: 'chrome', browserVersion: 'latest', platformName: 'WIN10' }], /** * test configurations */ logLevel: 'silent', coloredLogs: true, screenshotPath: 'screenshots', waitforTimeout: 10000, connectionRetryTimeout: 480000, framework: 'jasmine', services: [ ['testingbot'] ], user: 'api_key', key: 'api_secret', reporters: ['dot'], reporterOptions: { outputDir: './' }, jasmineNodeOpts: { defaultTimeoutInterval: 9999999 } }; **runner-specs/jasmine.spec.js** describe('google page', function() { it('should have the right title', async function () { await browser.url('https://www.google.com'); const title = await browser.getTitle(); expect(title).toBe('Google'); }); }); Now we can run this test on TestingBot. To start the test, please run this command: ~/node_modules/.bin/wdio run wdio.conf.js The test will now run on TestingBot. At the end of the test, the testname and success state will be available on TestingBot, together with a video and other meta-data. ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. When running mobile tests with WebdriverIO, especially on real devices, make sure to specify a large enough `connectionRetryTimeout` in case a device is in use: connectionRetryTimeout: 480000 ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a WebDriverIO test with our Tunnel: 1. Adjust your `wdio.conf.js` configuration to use `tbTunnel: true`. The [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) will automatically download and use the tunnel for your tests. **wdio.conf.js** exports.config = { services: [ ['testingbot', { tbTunnel: true }] ], user: 'api_key', key: 'api_secret' }; ## Run Tests in Parallel Parallel testing allows you to run multiple tests at the same time, significantly reducing your total test execution time. You can run the same test across different browser configurations, or run different tests on the same configuration — all simultaneously. TestingBot provides a large grid of browsers and devices, enabling you to run tests in parallel efficiently. This is one of our core features designed to help you test faster and ship more reliably. With WebDriverIO, you can enable parallel test execution by setting the `maxInstances` property in your `wdio.conf.js` file and specifying multiple `capabilities`. This defines how many instances of the same browser can run in parallel. We recommend setting this value to match the number of parallel sessions allowed by your TestingBot plan. exports.config = { maxInstances: 5, // Adjust this based on your TestingBot plan capabilities: [{ browserName: 'chrome', browserVersion: 'latest', platformName: 'WIN10' }, { browserName: 'firefox', browserVersion: 'latest', platformName: 'WIN10' }] }; ### Queuing Every TestingBot plan includes a fixed number of parallel test slots. If you exceed this limit, additional tests will be automatically queued and executed as soon as slots become available, no tests will be dropped or skipped. ## Mark tests as passed/failed As TestingBot has no way to determine whether your test passed or failed (it is determined by your business logic), we offer a way to send the test status back to TestingBot. This is useful if you want to see if a test succeeded or failed from the TestingBot member area. If you are using the [wdio-testingbot-service](https://webdriver.io/docs/testingbot-service/) then your tests will automatically report back meta-data to TestingBot (like test success, name, stacktrace, ...) ## Common errors Below are some common errors you might encounter when running WebDriverIO tests on TestingBot: - `UND_ERR_HEADERS_TIMEOUT` **Problem:** This error indicates that WebdriverIO did not receive a response in time. This might happen when requesting a device that is currently in use, or in case you are trying to run more tests in parallel than your plan allows and the tests have been [queued](https://testingbot.com#queuing) for a long time. **Solution:** You can try adding the `connectionRetryTimeout` in your WebDriverIO configuration with a high enough value: connectionRetryTimeout: 480000 ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/jest # Jest Testing See the TestingBot [Jest example repository](https://github.com/testingbot/jest-js-testingbot-example) for an example on how to run Jest tests with remote TestingBot browsers. [Jest](https://jestjs.io/) is a popular open-source testing framework for JavaScript applications, developed and maintained by Facebook. It is widely used for testing React applications but is versatile enough to test any JavaScript codebase. Jest provides a simple, intuitive API for writing unit tests, integration tests and end-to-end tests. ## Setting up Jest To run Jest tests with WebDriver, you first have to make sure both the Jest NPM package and the Selenium WebDriver NPM package are added to your project. npm install --save-dev jest selenium-webdriver You can now add a `jest.config.js` configuration file, which consists of a few options that Jest will use. module.exports = { testEnvironment: 'node', testTimeout: 60000, // Extend timeout for Selenium tests coverageProvider: "v8", maxConcurrency: 5, maxWorkers: 5, testPathIgnorePatterns: ["/node_modules/"] }; ### Jest Tests Now we can create our first Jest test. We'll create a new file in a directory called ` __tests__ `, called `single.test.js` const { Builder, By } = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); describe("TestingBot example test", () => { let driver; beforeAll(async () => { let options = new chrome.Options(); options.setBrowserVersion('latest'); options.setPlatformName('WIN10'); options.set('tb:options', { 'key': process.env.TESTINGBOT_KEY, 'secret': process.env.TESTINGBOT_SECRET, 'name': 'Jest Sample Test' }); driver = await new Builder() .usingServer('https://hub.testingbot.com/wd/hub') .setChromeOptions(options) .build(); }); afterAll(async () => { await driver.quit(); }); test("example test", async () => { await driver.get("https://testingbot.com"); await driver.findElement(By.css("a.button.button-trial")).click(); expect(await driver.getCurrentUrl()).toBe( "https://testingbot.com/users/sign_up" ); }); }); This example test will run on a remote Chrome browser on Windows 10 in the TestingBot cloud. The browser will navigate to the TestingBot website, click a button and verify the URL. ### Run Jest test Now that we have a test, we can run it on TestingBot. Before we can do this, make sure you get your key and secret from the TestingBot dashboard, to authenticate with the remote browser grid. Now we can run the test: TESTINGBOT_KEY=... TESTINGBOT_SECRET=... jest ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a Jest test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: driver = await new Builder() .usingServer('http://localhost:4445/wd/hub') .setChromeOptions(options) .build(); ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. By default, Jest will run all tests simultaneously. You can use Jest's [Sharding option](https://jestjs.io/docs/cli#--shard) to group tests together. For example, to split the suite into five shards, each running one fifth of the tests: jest --shard=1/5 jest --shard=2/5 jest --shard=3/5 jest --shard=4/5 jest --shard=5/5 ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [CodeceptJS](https://testingbot.com/support/web-automate/selenium/nodejs/codeceptjs) Run acceptance tests with CodeceptJS on TestingBot. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/nodejs/testcafe # TestCafe TestCafe is a NodeJS framework to do automate end-to-end web testing. You can write tests in either Javascript or TypeScript and is very easy to install and use. To get started, make sure you have: - NodeJS installed - Java (8 or higher) installed ## Install TestCafe To install TestCafe and the TestingBot plugin, please use this command: npm install -g testcafe testcafe-browser-provider-testingbot Once this is installed, you can start using TestCafe to run tests on TestingBot. ## Configure the TestCafe + TestingBot plugin Please add these 2 environment variables to authenticate to our browser grid: export TB_KEY=YOUR-TESTINGBOT-KEY export TB_SECRET=YOUR-TESTINGBOT-SECRET These two environment variables are required, however the plugin can be further configured with these environment variables as well: - `TB_TEST_NAME`: the text that will be displayed as Test Name in the dashboard. - `TB_BUILD`: you can add the tests as part of a build. - `SELENIUM_CAPABILITIES`: path to a file which contains a JSON formatted object with the capabilities you want to use. By default it will look for `capabilities.json`. - `TB_SCREEN_RESOLUTION`: set the VMs to a specific screen resolution. ## Test Example Please see this sample test, which you can use to run a test on our browser grid: import { Selector } from 'testcafe'; fixture `Getting Started` .page `http://devexpress.github.io/testcafe/example`; test('My first test', async t => { await t .typeText('#developer-name', 'John Smith') .click('#submit-button') // Use the assertion to check if the actual header text is equal to the expected one .expect(Selector('#article-header').innerText).eql('Thank you, John Smith!'); }); Now you can run this test on TestingBot: testcafe "testingbot:chrome@83:WIN10" 'example.js' TestCafe will start a [TestingBot Tunnel](https://testingbot.com/support/tunnel), then start a new Windows 10 VM on TestingBot with Chrome 83 and run the test. You will see a video recording of the test in the member dashboard, together with screenshots and logs. ## Specify Browsers & Devices With our TestCafe plugin, you can use a file called [capabilities.json](https://github.com/testingbot/testcafe-browser-provider-testingbot/blob/master/capabilities.json) where you can specify a JSON object with capabilities for each browser you want to use. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run multiple tests simultaneously, you can specify multiple browsers, like this: testcafe "testingbot:chrome@109:WIN10","testingbot:firefox@110:CATALINA" 'path/to/test/file.js' ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Other NodeJS Framework examples - [WebDriverIO](https://testingbot.com/support/web-automate/selenium/nodejs/webdriverio) With WebDriverIO you can run Mocha, Jasmine and Cucumber tests. - [Protractor](https://testingbot.com/support/web-automate/selenium/nodejs/protractor) Protractor is an end-to-end test framework for AngularJS applications. Protractor is a NodeJS program built on top of WebDriverJS. - [Soda](https://testingbot.com/support/web-automate/selenium/nodejs/soda) Selenium Node Adapter. A light-weight Selenium RC client for NodeJS. - [Nightwatch](https://testingbot.com/support/web-automate/selenium/nodejs/nightwatch) Nightwatch is an automated testing framework written in NodeJS. - [WD.js](https://testingbot.com/support/web-automate/selenium/nodejs/wd) WD.js is a NodeJS client for WebDriver/Selenium. - [Hermione](https://testingbot.com/support/web-automate/selenium/nodejs/hermione) Hermione is a Test Framework similar to WebDriverIO, with automatic test retries and plugins. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp # C# Automated Testing With TestingBot you can easily run your automated tests with [any C# test framework](https://testingbot.com#list). [Command Line](https://testingbot.com#)[Visual Studio](https://testingbot.com#) TestingBot has created a sample Visual Studio project to help you get started with C# and .NET Selenium testing. [Download ZIP](https://github.com/testingbot/nunit-example/archive/refs/heads/master.zip) You can import this project into Visual Studio and run the tests directly. To run your tests with C# and .NET, you need to have the [.NET SDK](https://dotnet.microsoft.com/download) installed on your machine. - **On Windows:** - Download the [.NET SDK](https://dotnet.microsoft.com/en-us/download) installer and run it. - Or use the `winget` command: `winget install Microsoft.DotNet.SDK.9` - **On MacOS:** `brew install dotnet` - **On Linux:** `sudo apt-get install dotnet-sdk-9.0` After installing the .NET SDK, you can create a new NUnit test project using the command line: dotnet new nunit -n SeleniumTest cd SeleniumTest Next, add the Selenium WebDriver packages to your project: dotnet add package Selenium.WebDriver dotnet add package Selenium.Support Replace the contents of `UnitTest1.cs` with the example code below, then run your tests with: TB_KEY=... TB_SECRET=... dotnet test **Requirements:** The examples on this page require .NET 6.0 or higher (recommended: .NET 8.0+). ## Selenium C# Example The example below shows how to run a simple Selenium test using C# on TestingBot. It will instruct a remote browser to navigate to Google, mark the test as passed and then close the remote browser. using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; namespace SeleniumNunit { [TestFixture] public class ExampleTest { private IWebDriver? Driver; [Test] public void SampleTest() { ChromeOptions options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name }); Driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), options); Driver.Navigate().GoToUrl("https://www.google.com"); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } Depending on the browser you want to test on, you may want to use [a different DriverOptions class](https://www.selenium.dev/documentation/webdriver/drivers/options/): browserName | className || Safari | `OpenQA.Selenium.Safari.SafariOptions` | | Chrome | `OpenQA.Selenium.Chrome.ChromeOptions` | | Firefox | `OpenQA.Selenium.Firefox.FirefoxOptions` | | IE | `OpenQA.Selenium.IE.InternetExplorerOptions` | | Edge | `OpenQA.Selenium.Edge.EdgeOptions` | Make sure to always stop your test (`Driver.Dispose()`), otherwise it will continue running, leading to a timeout. ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using NUnit.Framework; using NUnit.Framework.Interfaces; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; namespace SeleniumNunit { [TestFixture] public class ExampleTest { private IWebDriver? Driver; [Test] public void SampleTest() { ChromeOptions options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = TestContext.CurrentContext.Test.Name }); Driver = new RemoteWebDriver(new Uri("http://localhost:4445/wd/hub"), options); Driver.Navigate().GoToUrl("https://www.google.com"); Assert.Pass(); } [TearDown] public void CleanUpAfterEveryTestMethod() { if (Driver != null) { var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); Driver.Dispose(); } } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. ### NUnit Parallel Testing NUnit supports parallel test execution out of the box using the `[Parallelizable]` attribute: // Run all tests in this class in parallel with other classes [TestFixture] [Parallelizable(ParallelScope.All)] public class ParallelTests { [Test] public void Test1() { /* ... */ } [Test] public void Test2() { /* ... */ } } // Or at assembly level in AssemblyInfo.cs: [assembly: Parallelizable(ParallelScope.Fixtures)] [assembly: LevelOfParallelism(4)] // Run up to 4 tests concurrently You can also run tests in parallel from the command line: dotnet test -- NUnit.NumberOfTestWorkers=4 ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { if (Driver != null) { bool passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; // Logs the result to TestingBot ((IJavaScriptExecutor)Driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); // Terminates the remote webdriver session Driver.Dispose(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/pnunit TestingBot does not recommend using PNUnit as the PNUnit project seems to be deprecated. Instead, you can use the [NUnit parallel option](https://testingbot.com/support/web-automate/selenium/csharp/nunit#parallel) which can run tests in parallel. # PNUnit Automated Testing PNUnit is an expansion to the NUnit framework. The "P" stands for "Parallel" and basically means that you can run several tests at the same time on our Selenium grid. More information regarding PNUnit is available on the [PNUnit website](https://www.plasticscm.com/documentation/technical-articles/pnunit-parallel-nunit). It's really easy to convert your current NUnit Selenium tests to PNUnit Selenium Tests. - Modify your test to take parameters from a config file (browserName, version, platform, ...) - Create the config file (shown in the example below), specifying which browsers you want to test on. ### Example code using NUnit.Framework; using PNUnit.Framework; using System; using System.Web; using System.Text; using System.Net; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace Test { [TestFixture()] public class TestingBotTest { private IWebDriver driver; private string[] testParams; [SetUp] public void Init() { testParams = PNUnitServices.Get().GetTestParams(); String params1 = String.Join(",", testParams); Console.WriteLine(params1); String browser = testParams[0]; String version = testParams[1]; String os = testParams[2]; DesiredCapabilities capability = new DesiredCapabilities(); capability.SetCapability("browserName", browser); capability.SetCapability(CapabilityType.Version, version); capability.SetCapability("platform", os); capability.SetCapability("api_key", "api_key"); capability.SetCapability("api_secret", "api_secret"); Console.WriteLine("Capabilities" + capability.ToString()); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub/"), capability); } [Test] public void TestCase() { driver.Navigate().GoToUrl("https://www.google.com"); StringAssert.Contains("Google", driver.Title); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); } [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } } } Now we have to tell PNunit which parameters we want to send with the test: Testing TestFF-Win8 SeleniumTest.dll Test.TestingBotTest.TestCase localhost:8080 firefox latest WIN8 TestChrome-Win7 SeleniumTest.dll Test.TestingBotTest.TestCase localhost:8080 chrome latest VISTA ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. DesiredCapabilities capability = new DesiredCapabilities(); capability.SetCapability("browserName", browser); capability.SetCapability(CapabilityType.Version, version); capability.SetCapability("platform", os); capability.SetCapability("api_key", "api_key"); capability.SetCapability("api_secret", "api_secret"); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a PNUnit test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using NUnit.Framework; using PNUnit.Framework; using System; using System.Web; using System.Text; using System.Net; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace Test { [TestFixture()] public class TestingBotTest { private IWebDriver driver; private string[] testParams; [SetUp] public void Init() { testParams = PNUnitServices.Get().GetTestParams(); String params1 = String.Join(",", testParams); Console.WriteLine(params1); String browser = testParams[0]; String version = testParams[1]; String os = testParams[2]; DesiredCapabilities capability = new DesiredCapabilities(); capability.SetCapability("browserName", browser); capability.SetCapability(CapabilityType.Version, version); capability.SetCapability("platform", os); capability.SetCapability("api_key", "api_key"); capability.SetCapability("api_secret", "api_secret"); Console.WriteLine("Capabilities" + capability.ToString()); driver = new RemoteWebDriver(new Uri("http://localhost:4445/wd/hub/"), capability); } [Test] public void TestCase() { driver.Navigate().GoToUrl("https://www.google.com"); StringAssert.Contains("Google", driver.Title); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); } [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } } } ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/nunit # C# Automated Testing with NUnit NUnit is a unit-test framework designed for all the .NET languages. It is written in C# and built to use many of the .NET language features. For example: it allows you to use custom attributes and other reflection-related capabilities. Please visit the [official NUnit website](https://nunit.org/) for more documentation about the framework. See our [NUnit example repository](https://github.com/testingbot/nunit-example) for a simple example on how to run NUnit tests on TestingBot. ## Prerequisites To get started, you need to download and install these components: [Command Line](https://testingbot.com#)[Visual Studio](https://testingbot.com#) TestingBot has created a sample [Visual Studio](https://www.visualstudio.com/) project to help you get started with C# and .NET Selenium testing. [Download ZIP](https://github.com/testingbot/nunit-example/archive/refs/heads/master.zip) You can import this project into Visual Studio and run the tests directly. To run your tests with C# and .NET, you need to have the [.NET SDK](https://dotnet.microsoft.com/download) installed on your machine. - **On Windows:** - Download the [.NET SDK](https://dotnet.microsoft.com/en-us/download) installer and run it. - Or use the `winget` command: `winget install Microsoft.DotNet.SDK.9` - **On MacOS:** `brew install dotnet` - **On Linux:** `sudo apt-get install dotnet-sdk-9.0` After installing the .NET SDK, you can create a new C# project using the command line: dotnet new console -n SeleniumTest Next, add the necessary Selenium WebDriver packages to your project: cd SeleniumTest dotnet add package Selenium.WebDriver dotnet add package Selenium.Support dotnet add package NUnit ## Example NUnit test Below is a simple example of an NUnit test that uses Selenium WebDriver to open Google and search for "TestingBot". using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample; public class Tests { [TestFixture("chrome", "latest", "Windows 10")] public class TbNUnit_Test { private IWebDriver driver; private string browser; private string version; private string os; public TbNUnit_Test(String browser, String version, String os) { this.browser = browser; this.version = version; this.os = os; } [SetUp] public void Init() { DriverOptions browserOptions = new ChromeOptions() { BrowserVersion = this.version, PlatformName = this.os }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "3.14.0" }; browserOptions.AddAdditionalOption("tb:options", tbOptions); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); } [Test] public void GoogleTest() { driver.Navigate().GoToUrl("http://www.google.com"); Assert.That(driver.Title, Is.EqualTo("Google")); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); } [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); driver.Dispose(); } } } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. var chromeOptions = new ChromeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10" }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "3.14.0" }; Depending on the browser you want to test on, you might need to specify different browser options in your code: - [ChromeOptions](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/Chrome/ChromeOptions.cs) for Chrome browsers - [EdgeOptions](https://learn.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options) for Edge browsers - [EdgeOptions](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/Firefox/FirefoxOptions.cs) for Firefox browsers - [InternetExplorerOptions](https://learn.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ie-mode?tabs=c-sharp) for IE browsers - `OperaOptions` for Opera browsers - [SafariOptions](https://github.com/SeleniumHQ/selenium/blob/trunk/dotnet/src/webdriver/Safari/SafariOptions.cs) for Safari browsers ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Looking to generate more custom capabilities? Use the [Selenium capabilities generator](https://testingbot.com/support/web-automate/selenium/capabilities). ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample; public class Tests { [TestFixture("chrome", "latest", "Windows 10")] public class TbNUnit_Test { private IWebDriver driver; private string browser; private string version; private string os; public TbNUnit_Test(String browser, String version, String os) { this.browser = browser; this.version = version; this.os = os; } [SetUp] public void Init() { DriverOptions browserOptions = new ChromeOptions() { BrowserVersion = this.version, PlatformName = this.os }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "3.14.0" }; browserOptions.AddAdditionalOption("tb:options", tbOptions); driver = new RemoteWebDriver(new Uri("http://localhost:4445/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); } [Test] public void GoogleTest() { driver.Navigate().GoToUrl("http://www.google.com"); Assert.That(driver.Title, Is.EqualTo("Google")); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); } [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); driver.Dispose(); } } } } ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. NUnit provides a `[assembly: Parallelizable(ParallelScope.Fixtures)]` option to specify tests should run in parallel. More information is available in the [NUnit Parallelizable documentation](https://docs.nunit.org/articles/nunit/technical-notes/usage/Framework-Parallel-Test-Execution.html#specifying-parallelism-at-multiple-test-levels). ### Queuing Every plan we provide comes with a limited amount of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/mbunit # C# Automated Testing with MbUnit MbUnit (previously named GUnit) is a generative test unit framework, built for C sharp testing. MbUnit implements the Simple Test Pattern and makes it really easy to use fixtures. ## Your first MbUnit test Please see the example test below, using MbUnit and Gallio framework: **SingleTest.cs** : using Gallio.Framework; using MbUnit.Framework; using MbUnit.Framework.ContractVerifiers; using OpenQA.Selenium; using System.Collections.Generic; namespace TestingBot { [TestFixture] public class SingleTest : TestingBotMBUnitTest { public SingleTest() : base("single", "chrome") { } [Test] public void SearchGoogle() { driver.Navigate().GoToUrl("https://www.google.com/ncr"); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); System.Threading.Thread.Sleep(5000); Assert.AreEqual("TestingBot - Google Search", driver.Title); } } } **TestingBotMBUnitTest.cs** : using Gallio.Framework; using MbUnit.Framework; using MbUnit.Framework.ContractVerifiers; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Text; using TestingBot; namespace TestingBot { [TestFixture] public class TestingBotMBUnitTest { protected IWebDriver driver; protected string profile; protected string environment; public TestingBotMBUnitTest(string profile, string environment = "chrome") { this.profile = profile; this.environment = environment; } [FixtureSetUp] public void Init() { DesiredCapabilities capability = new DesiredCapabilities(); String key = Environment.GetEnvironmentVariable("TB_KEY"); if(key == null) { key = ConfigurationManager.AppSettings.Get("key"); } String secret = Environment.GetEnvironmentVariable("TB_SECRET"); if (secret == null) { secret = ConfigurationManager.AppSettings.Get("secret"); } capability.SetCapability("key", key); capability.SetCapability("secret", secret); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub/"), capability); } [FixtureTearDown] public void Cleanup() { driver.Quit(); } } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. IWebDriver driver; DesiredCapabilities desiredCap = new DesiredCapabilities(); desiredCap.SetCapability("key", "key"); desiredCap.SetCapability("secret", "secret"); driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub/"), desiredCap ); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: driver = new RemoteWebDriver(new Uri("http://localhost:4445/wd/hub/"), capability); ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. Please see our [PNUnit documentation](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) for parallel testing. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = true || false; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [MbUnit](https://testingbot.com/support/web-automate/selenium/csharp/mbunit) MbUnit is a generative test unit framework, built for C sharp testing. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/mstest # C# Automated Testing with MSTest MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. It is also referred to as Visual Studio Unit Testing Framework and is popular with developers using the Visual Studio IDE. MSTest V2 is open-sourced and available on [GitHub](https://github.com/Microsoft/testfx). With MSTest V2 you can easily run tests in parallel, using In-Assembly Parallel (via `Annotations` or `RunSettings`). ## Installation To get started with MSTest, you'll need to make sure that `MSTest Framework` and `MSTest Adapter` are installed. You can install the packages via the commandline or with NuGet: - MSTest.TestAdapter - MSTest.TestFramework - Microsoft.NET.Test.Sdk ## Your first MSTest test Please see the example test below, using MSTest. The test will start 3 browsers, visit our homepage and print the title. **SingleTest.cs** : using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using System.Threading.Tasks; using System.Text.RegularExpressions; using OpenQA.Selenium.Support.UI; using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Remote; [assembly: Parallelize(Workers = 0, Scope = ExecutionScope.ClassLevel)] namespace MS_Test_Cross_Browser { IWebDriver driver; String key = "key"; String secret = "secret"; DesiredCapabilities capabilities; [TestInitialize] public void setupInit() { capabilities = new DesiredCapabilities(); capabilities.SetCapability("key", key); capabilities.SetCapability("secret", secret); } [DataTestMethod] [DataRow("chrome", "latest", "Windows 10")] [DataRow("MicrosoftEdge", "latest-1", "Windows 10")] [DataRow("Firefox", "latest", "BIGSUR")] [TestMethod] public void Single_Test(String browser, String version, String os) { capabilities.SetCapability("browserName", browser); capabilities.SetCapability("version", version); capabilities.SetCapability("platform", os); capabilities.SetCapability("name", "MsTest with TestingBot"); driver = new RemoteWebDriver(new Uri("https://" + username + ":" + accesskey + "@hub.testingbot.com"), capabilities, TimeSpan.FromSeconds(20000)); driver.Url = "https://testingbot.com"; /* Perform wait to check the output */ System.Threading.Thread.Sleep(2000); Console.WriteLine(driver.Title); } } ## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. IWebDriver driver; DesiredCapabilities desiredCap = new DesiredCapabilities(); desiredCap.SetCapability("key", "key"); desiredCap.SetCapability("secret", "secret"); driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub/"), desiredCap ); To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a C# test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: driver = new RemoteWebDriver(new Uri("http://localhost:4445/wd/hub/"), capability); ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To modify the number of parallel tests with MSTest, please use the `Parallelize annotation`: [assembly: Parallelize(Workers = 5, Scope = ExecutionScope.MethodLevel)] This will run the test on 5 workers (= 5 parallel sessions). ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = true || false; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/xunit # C# Automated Testing with xUnit.net [xUnit.net](https://xunit.net/) is a free, open-source, community-focused unit testing framework for .NET. It is the successor to NUnit and was written by the original inventor of NUnit v2. xUnit.net is widely used in the .NET ecosystem and offers modern features like: - Built-in support for parallel test execution - Theory tests with `[InlineData]` for data-driven testing - Constructor/Dispose pattern for test setup and teardown - Fixtures for sharing context between tests ## Installation Create a new xUnit test project and add the required packages: # Create a new xUnit test project dotnet new xunit -n SeleniumTests cd SeleniumTests # Add Selenium WebDriver packages dotnet add package Selenium.WebDriver dotnet add package Selenium.Support Or add these packages to your `.csproj` file: **Requirements:** xUnit 2.x requires .NET 6.0 or higher. The examples use modern C# features like nullable reference types. ## Your first xUnit test The example below shows a complete xUnit test that connects to TestingBot and runs a simple browser test. xUnit uses constructor/destructor (or `IDisposable`) for setup and teardown instead of attributes. **GoogleTest.cs** : using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; using Xunit; namespace SeleniumTests; public class GoogleTest : IDisposable { private readonly IWebDriver _driver; private readonly string _sessionId; public GoogleTest() { // Configure Chrome options var options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = "xUnit Google Test" }); // Connect to TestingBot _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); _sessionId = ((RemoteWebDriver)_driver).SessionId.ToString(); } [Fact] public void GoogleTitle_ShouldContainGoogle() { _driver.Navigate().GoToUrl("https://www.google.com"); Assert.Contains("Google", _driver.Title); } public void Dispose() { if (_driver != null) { // Mark test as passed (simplified - see API section for proper implementation) ((IJavaScriptExecutor)_driver).ExecuteScript("tb:test-result=passed"); _driver.Dispose(); } } } Run your test with: TB_KEY=your_key TB_SECRET=your_secret dotnet test ## Data-Driven Testing with Theory xUnit's `[Theory]` attribute allows you to run the same test with different data. This is perfect for cross-browser testing: using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Edge; using OpenQA.Selenium.Remote; using Xunit; namespace SeleniumTests; public class CrossBrowserTest : IDisposable { private IWebDriver? _driver; [Theory] [InlineData("chrome", "latest", "WIN10")] [InlineData("firefox", "latest", "WIN10")] [InlineData("MicrosoftEdge", "latest", "WIN10")] [InlineData("safari", "latest", "SONOMA")] public void HomePage_ShouldLoad_OnAllBrowsers(string browser, string version, string platform) { // Create browser-specific options DriverOptions options = browser.ToLower() switch { "chrome" => new ChromeOptions(), "firefox" => new FirefoxOptions(), "microsoftedge" => new EdgeOptions(), "safari" => new SafariOptions(), _ => new ChromeOptions() }; options.BrowserVersion = version; options.PlatformName = platform; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = $"Cross-browser test - {browser}" }); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); _driver.Navigate().GoToUrl("https://testingbot.com"); Assert.Contains("TestingBot", _driver.Title); } public void Dispose() { if (_driver != null) { ((IJavaScriptExecutor)_driver).ExecuteScript("tb:test-result=passed"); _driver.Dispose(); } } } ## Specify Browsers & Devices To run tests on specific browsers and platforms, configure the appropriate `DriverOptions` class. // Chrome on Windows var chromeOptions = new ChromeOptions(); chromeOptions.BrowserVersion = "latest"; chromeOptions.PlatformName = "WIN10"; chromeOptions.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "YOUR_TB_KEY", ["secret"] = "YOUR_TB_SECRET" }); var driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions ); To see how to configure different browsers and platforms, use the picker below: ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites Use [TestingBot Tunnel](https://testingbot.com/support/tunnel) to securely test internal or staged websites that aren't publicly accessible. **1.** [Download the tunnel](https://testingbot.com/support/tunnel) and start it: java -jar testingbot-tunnel.jar key secret **2.** Update your test to connect through the tunnel (change the hub URL to `localhost:4445`): // Connect through the tunnel instead of directly to TestingBot var driver = new RemoteWebDriver( new Uri("http://localhost:4445/wd/hub"), options ); // Now you can access internal URLs driver.Navigate().GoToUrl("http://internal.yourcompany.com"); ## Run tests in Parallel xUnit runs tests in parallel by default. Tests in different test classes run in parallel, while tests in the same class run sequentially. ### Configure Parallelism Control parallel execution by adding an `xunit.runner.json` file to your project: { "parallelizeAssembly": true, "parallelizeTestCollections": true, "maxParallelThreads": 5 } Make sure to include it in your `.csproj`: ### Using Test Collections Group tests that shouldn't run in parallel using `[Collection]`: // Tests in the same collection run sequentially [Collection("Sequential")] public class SequentialTests1 { } [Collection("Sequential")] public class SequentialTests2 { } // Tests without a collection run in parallel with other classes ### Queuing Every TestingBot plan has a limit on parallel tests. If you exceed this limit, additional tests are queued (up to 6 minutes) and run as slots become available. ## Mark tests as passed/failed To report test results to TestingBot, use JavaScript execution to set the test status: public class TestBase : IDisposable { protected IWebDriver Driver { get; } private bool _testPassed = true; public TestBase() { var options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "" }); Driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); } protected void MarkTestFailed() { _testPassed = false; } public void Dispose() { if (Driver != null) { var status = _testPassed ? "passed" : "failed"; ((IJavaScriptExecutor)Driver).ExecuteScript($"tb:test-result={status}"); Driver.Dispose(); } } } // Usage in test class public class MyTests : TestBase { [Fact] public void TestSomething() { try { Driver.Navigate().GoToUrl("https://example.com"); Assert.Equal("Example Domain", Driver.Title); } catch { MarkTestFailed(); throw; } } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/specflow **SpecFlow reached End of Life (EOL) on December 31, 2024.** For new projects, we recommend using [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll), the community-maintained successor to SpecFlow. Reqnroll is fully compatible with SpecFlow and provides an easy migration path. # Your first C# test with SpecFlow See our [SpecFlow example repository](https://github.com/testingbot/specflow-example) for a simple example on how to run SpecFlow tests in parallel on TestingBot. SpecFlow is an open-source .NET utility which allows you to write tests using Cucumber-compatible Gherkin syntax. ## Installation You can install SpecFlow via the [NuGet Gallery](https://www.nuget.org/) - Create a new project in Visual Studio. - In the Visual Studio Tools menu, go to **Library Package Manager \> Manage Nuget Package for Solution**. - This will open the Manage NuGet Packages dialog. Click **Online** , then **Next**. - In the **Search Packages** field, enter **SpecFlow** and click **Search**. - Select **SpecFlow** from the search results and click **Install**. For more details, please visit [SpecFlow installation Document](https://specflow.org/getting-started/#InstallSetup). ### Sample Test This is a sample test case in SpecFlow: Feature: Google Scenario Outline: Can find search results Given I am on the google page for and When I search for "TestingBot" Then I should see title "TestingBot - Google Search" Examples: | profile | environment | | single | chrome | [Binding] public class SingleSteps { private IWebDriver _driver; readonly TestingBotDriver _tbDriver; public SingleSteps() { _tbDriver = (TestingBotDriver)ScenarioContext.Current["tbDriver"]; } [Given(@"I am on the google page for (.*) and (.*)")] public void GivenIAmOnTheGooglePage(string profile, string environment) { _driver = _tbDriver.Init(profile, environment); _driver.Navigate().GoToUrl("https://www.google.com/ncr"); } [When(@"I search for ""(.*)""")] public void WhenISearchFor(string keyword) { var q = _driver.FindElement(By.Name("q")); q.SendKeys(keyword); q.Submit(); } [Then(@"I should see title ""(.*)""")] public void ThenIShouldSeeTitle(string title) { Thread.Sleep(5000); Assert.That(_driver.Title, Is.EqualTo(title)); } } Now you need to create the **TestingBotDriver** we will be using: [Binding] public sealed class TestingBot { private TestingBotDriver tbDriver; private string[] tags; [BeforeScenario] public void BeforeScenario() { tbDriver = new TestingBotDriver(ScenarioContext.Current); ScenarioContext.Current["tbDriver"] = tbDriver; } [AfterScenario] public void AfterScenario() { tbDriver.Cleanup(); } } public class TestingBotDriver { private IWebDriver driver; private string profile; private string environment; private ScenarioContext context; public TestingBotDriver(ScenarioContext context) { this.context = context; } public IWebDriver Init(string profile, string environment) { NameValueCollection caps = ConfigurationManager.GetSection("capabilities/" + profile) as NameValueCollection; NameValueCollection settings = ConfigurationManager.GetSection("environments/" + environment) as NameValueCollection; DesiredCapabilities capability = new DesiredCapabilities(); foreach (string key in caps.AllKeys) { capability.SetCapability(key, caps[key]); } foreach (string key in settings.AllKeys) { capability.SetCapability(key, settings[key]); } String key = Environment.GetEnvironmentVariable("TB_KEY"); if (key == null) { key = ConfigurationManager.AppSettings.Get("key"); } String secret = Environment.GetEnvironmentVariable("TB_SECRET"); if (secret == null) { secret = ConfigurationManager.AppSettings.Get("secret"); } capability.SetCapability("key", key); capability.SetCapability("secret", secret); driver = new RemoteWebDriver(new Uri("http://" + ConfigurationManager.AppSettings.Get("server") + "/wd/hub/"), capability); return driver; } public void Cleanup() { driver.Quit(); } } Now we need to create the **config file** which the code above uses to determine various settings.
## Specify Browsers & Devices To let TestingBot know on which browser/platform/device you want to run your test on, you need to specify the browsername, version, OS and other optional options in the capabilities field. To see how to do this, please select a combination of browser, version and platform in the drop-down menus below. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites We've built [TestingBot Tunnel](https://testingbot.com/support/tunnel), to provide you with a secure way to run tests against your staged/internal webapps. Please see our [TestingBot Tunnel documentation](https://testingbot.com/support/tunnel) for more information about this easy to use tunneling solution. The example below shows how to easily run a SpecFlow test with our Tunnel: 1. [Download our tunnel](https://testingbot.com/support/tunnel) and start the tunnel: java -jar testingbot-tunnel.jar key secret 2. Adjust your test: instead of pointing to `'hub.testingbot.com/wd/hub'` like the example above - change it to point to your tunnel's IP address. Assuming you run the tunnel on the same machine you run your tests, change to `'localhost:4445/wd/hub'`. localhost is the machine running the tunnel, 4445 is the default port of the tunnel. This way your test will go securely through the tunnel to TestingBot and back: ## Run tests in Parallel Parallel Testing means running the same test, or multiple tests, simultaneously. This greatly reduces your total testing time. You can run the same tests on all different browser configurations or run different tests all on the same browser configuration. TestingBot has a large grid of machines and browsers, which means you can use our service to do efficient parallel testing. It is one of the key features we provide to greatly cut down on your total testing time. To run multiple tests at the same time with SpecFlow, modify the **config file** like this: // App.config
// Add to AssemblyInfo.cs [assembly: Parallelizable(ParallelScope.Fixtures)] The test cases you want to run in parallel need to be written like this: // Google Feature for parallel run Feature: Google Scenario Outline: Can find search results Given I am on the google page for and When I search for "TestingBot" Then I should see title "TestingBot - Google Search" Examples: | profile | environment | | parallel | chrome | | parallel | firefox | | parallel | safari | | parallel | edge | You can now run the tests in parallel by running the tests with fixture **parallel** from **Test Explorer**. ### Queuing Every plan we provide comes with a limit of parallel tests. If you exceed the number of parallel tests assigned to your account, TestingBot will queue the additional tests (for up to 6 minutes) and run the tests as soon as slots become available. ## Mark tests as passed/failed To see if a test passed or not in our member area, or to send additional meta-data to TestingBot, you can use our API. Please see the example below on how to notify TestingBot about the test success state: [TearDown] public void CleanUp() { bool passed = TestContext.CurrentContext.Result.Status == TestStatus.Passed; try { // Logs the result to TestingBot ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=" + (passed ? "passed" : "failed")); } finally { // Terminates the remote webdriver session driver.Quit(); } } ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [PNunit](https://testingbot.com/support/web-automate/selenium/csharp/pnunit) With PNUnit you can run several tests in parallel. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow allows you to run Automated .NET tests using Cucumber-compatible Gherkin syntax. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [Reqnroll](https://testingbot.com/support/web-automate/selenium/csharp/reqnroll) Reqnroll is the community-maintained successor to SpecFlow for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/csharp/reqnroll # C# BDD Testing with Reqnroll [Reqnroll](https://reqnroll.net/) is an open-source .NET test automation framework for Behavior-Driven Development (BDD). It is the community-maintained successor to SpecFlow and is fully compatible with Gherkin syntax. Reqnroll works with all major .NET versions (.NET 6.0, 7.0, 8.0, 9.0) and integrates with popular test frameworks: - NUnit - xUnit - MSTest - TUnit **Migrating from SpecFlow?** Reqnroll is based on the SpecFlow codebase and provides an easy migration path. See the [migration section](https://testingbot.com#migration) below. ## Installation First, install the **Reqnroll for Visual Studio 2022** extension from the Visual Studio Marketplace to get syntax highlighting, navigation and project templates. ### Create a new project Create a new test project and add the required packages: # Create a new NUnit test project dotnet new nunit -n ReqnrollTests cd ReqnrollTests # Add Reqnroll with NUnit integration dotnet add package Reqnroll.NUnit # Add Selenium WebDriver packages dotnet add package Selenium.WebDriver dotnet add package Selenium.Support Or add these packages to your `.csproj` file: Alternative packages for other test frameworks: - `Reqnroll.xUnit` - for xUnit 2.x - `Reqnroll.xUnit.v3` - for xUnit 3.x - `Reqnroll.MsTest` - for MSTest - `Reqnroll.TUnit` - for TUnit ## Your first Reqnroll test Reqnroll tests consist of three parts: a Feature file (Gherkin), Step Definitions (C#), and a Driver helper class. ### 1. Feature File Create a `Features` folder and add `Search.feature`: Feature: Google Search Scenario: Search for TestingBot Given I am on the Google homepage When I search for "TestingBot" Then the page title should contain "TestingBot" Scenario Outline: Search on multiple browsers Given I am using on And I am on the Google homepage When I search for "TestingBot" Then the page title should contain "TestingBot" Examples: | browser | platform | | chrome | WIN10 | | firefox | WIN10 | | safari | TAHOE | ### 2. Driver Helper Class Create a helper class to manage the WebDriver connection to TestingBot: using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; using OpenQA.Selenium.Remote; namespace ReqnrollTests.Support; public class TestingBotDriver : IDisposable { public IWebDriver Driver { get; private set; } private bool _testPassed = true; public void Initialize(string browser = "chrome", string version = "latest", string platform = "WIN10") { DriverOptions options = browser.ToLower() switch { "firefox" => new FirefoxOptions(), "safari" => new SafariOptions(), _ => new ChromeOptions() }; options.BrowserVersion = version; options.PlatformName = platform; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = Environment.GetEnvironmentVariable("TB_KEY") ?? "", ["secret"] = Environment.GetEnvironmentVariable("TB_SECRET") ?? "", ["name"] = "Reqnroll Test" }); Driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); } public void MarkTestFailed() => _testPassed = false; public void Dispose() { if (Driver != null) { var status = _testPassed ? "passed" : "failed"; ((IJavaScriptExecutor)Driver).ExecuteScript($"tb:test-result={status}"); Driver.Dispose(); } } } ### 3. Step Definitions Create `StepDefinitions/SearchSteps.cs`: using OpenQA.Selenium; using Reqnroll; using ReqnrollTests.Support; namespace ReqnrollTests.StepDefinitions; [Binding] public class SearchSteps { private readonly TestingBotDriver _tbDriver; public SearchSteps(TestingBotDriver tbDriver) { _tbDriver = tbDriver; } [Given("I am on the Google homepage")] public void GivenIAmOnTheGoogleHomepage() { if (_tbDriver.Driver == null) _tbDriver.Initialize(); _tbDriver.Driver.Navigate().GoToUrl("https://www.google.com"); } [Given("I am using (.*) on (.*)")] public void GivenIAmUsingBrowserOnPlatform(string browser, string platform) { _tbDriver.Initialize(browser, "latest", platform); } [When("I search for {string}")] public void WhenISearchFor(string searchTerm) { var searchBox = _tbDriver.Driver.FindElement(By.Name("q")); searchBox.SendKeys(searchTerm); searchBox.Submit(); } [Then("the page title should contain {string}")] public void ThenThePageTitleShouldContain(string expectedText) { // Wait for results to load Thread.Sleep(2000); Assert.That(_tbDriver.Driver.Title, Does.Contain(expectedText)); } } ### 4. Hooks for Setup/Teardown Create `Hooks/TestHooks.cs` to manage driver lifecycle: using Reqnroll; using ReqnrollTests.Support; namespace ReqnrollTests.Hooks; [Binding] public class TestHooks { private readonly TestingBotDriver _tbDriver; public TestHooks(TestingBotDriver tbDriver) { _tbDriver = tbDriver; } [AfterScenario] public void AfterScenario(ScenarioContext scenarioContext) { if (scenarioContext.TestError != null) { _tbDriver.MarkTestFailed(); } _tbDriver.Dispose(); } } Run your tests with: TB_KEY=your_key TB_SECRET=your_secret dotnet test ## Specify Browsers & Devices Configure browsers and platforms using Selenium 4's browser-specific options classes: - `ChromeOptions` for Chrome - `FirefoxOptions` for Firefox - `EdgeOptions` for Microsoft Edge - `SafariOptions` for Safari Example using ChromeOptions: var options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "YOUR_TB_KEY", ["secret"] = "YOUR_TB_SECRET", ["name"] = "My Reqnroll Test" }); var driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); To see how to configure different browsers and platforms, use the picker below: ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Testing Internal Websites Use [TestingBot Tunnel](https://testingbot.com/support/tunnel) to securely test internal or staged websites. **1.** [Download the tunnel](https://testingbot.com/support/tunnel) and start it: java -jar testingbot-tunnel.jar key secret **2.** Update your driver initialization to connect through the tunnel: // Connect through the tunnel instead of directly to TestingBot Driver = new RemoteWebDriver( new Uri("http://localhost:4445/wd/hub"), options ); // Now you can access internal URLs in your tests Driver.Navigate().GoToUrl("http://internal.yourcompany.com"); ## Run tests in Parallel Reqnroll supports parallel test execution when using NUnit or xUnit as the test runner. ### NUnit Parallel Execution Add to your `AssemblyInfo.cs` or any file: using NUnit.Framework; [assembly: Parallelizable(ParallelScope.Fixtures)] [assembly: LevelOfParallelism(5)] Configure in `reqnroll.json`: { "$schema": "https://schemas.reqnroll.net/reqnroll-config-latest.json", "bindingCulture": { "name": "en-US" } } ### xUnit Parallel Execution Add `xunit.runner.json`: { "parallelizeAssembly": true, "parallelizeTestCollections": true, "maxParallelThreads": 5 } ### Queuing Every TestingBot plan has a limit on parallel tests. If you exceed this limit, additional tests are queued (up to 6 minutes) and run as slots become available. ## Mark tests as passed/failed Report test results to TestingBot using JavaScript execution in your `[AfterScenario]` hook: [Binding] public class TestHooks { private readonly TestingBotDriver _tbDriver; public TestHooks(TestingBotDriver tbDriver) { _tbDriver = tbDriver; } [AfterScenario] public void AfterScenario(ScenarioContext scenarioContext) { if (_tbDriver.Driver != null) { var status = scenarioContext.TestError == null ? "passed" : "failed"; ((IJavaScriptExecutor)_tbDriver.Driver).ExecuteScript($"tb:test-result={status}"); _tbDriver.Driver.Dispose(); } } } ## Migrating from SpecFlow Reqnroll is designed as a drop-in replacement for SpecFlow. Most projects can migrate with minimal changes: ### 1. Update NuGet Packages # Remove SpecFlow packages dotnet remove package SpecFlow dotnet remove package SpecFlow.NUnit # Add Reqnroll packages dotnet add package Reqnroll.NUnit ### 2. Update Namespaces Replace `TechTalk.SpecFlow` with `Reqnroll` in your code: // Before (SpecFlow) using TechTalk.SpecFlow; // After (Reqnroll) using Reqnroll; ### 3. Update Configuration Rename `specflow.json` to `reqnroll.json` and update the schema reference: { "$schema": "https://schemas.reqnroll.net/reqnroll-config-latest.json" } ### 4. Update Visual Studio Extension Install the "Reqnroll for Visual Studio 2022" extension and uninstall the SpecFlow extension. For a complete migration guide, see the [official SpecFlow to Reqnroll migration guide](https://reqnroll.net/news/2024/02/from-specflow-to-reqnroll-why-and-how/). ## Other C# Framework examples - [NUnit](https://testingbot.com/support/web-automate/selenium/csharp/nunit) An unit testing framework that is open source written in C#. - [xUnit](https://testingbot.com/support/web-automate/selenium/csharp/xunit) xUnit.net is a modern, extensible testing framework for .NET, widely used in the .NET ecosystem. - [MSTest](https://testingbot.com/support/web-automate/selenium/csharp/mstest) MSTest framework is a test framework which is included, by default, with Microsoft Visual Studio. - [SpecFlow](https://testingbot.com/support/web-automate/selenium/csharp/specflow) SpecFlow (deprecated) - the predecessor to Reqnroll for BDD testing with Gherkin syntax. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/selenium4 # Selenium 4 This page will help you in upgrading your existing Selenium WebDriver tests to use Selenium 4, with the [WebDriver W3C Protocol](https://www.w3.org/TR/webdriver1/). TestingBot has full support for this new Selenium version. Below is more information on how to make this transition. ## Updating your tests With the new W3C protocol, some restrictions apply to using capabilities with your test. Before the W3C protocol (the JSONWP protocol), you could simply add [all our custom TestingBot capabilities](https://testingbot.com/support/web-automate/selenium/test-options) to your test in the `desiredCapabilities`. With the new W3C protocol, only some W3C WebDriver capabilities are allowed inside the `capabilities`: - `browserName` - `browserVersion` - `platformName` - `acceptInsecureCerts` - `pageLoadStrategy` - `proxy` - `timeouts` - `unhandledPromptBehavior` All other capabilities are treated as [Extension capabilities](https://www.w3.org/TR/webdriver1/#dfn-extension-capability) and should be namespaced (include a vendor prefix). For [TestingBot specific capabilities](https://testingbot.com/support/web-automate/selenium/test-options), you'll need to wrap all capabilities inside a `tb:options` namespace. Please see the table below on how the capabilities need to be changed: Capability JSONWP | Capability W3C || `browserName` | `browserName` | | `version` | `browserVersion` | | `platform` | `platformName` | | `selenium-version`, `chromedriverVersion`, `extra`, `name` [and more](https://testingbot.com/support/web-automate/selenium/test-options) | "tb:options" : { "selenium-version": '...', "chromedriverVersion": '...', "extra": '...', "name": '...' } | ## Example [Legacy](https://testingbot.com#)[Selenium 4](https://testingbot.com#) #### Ruby #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = { :browserName => "chrome", :version => "latest-1", :platform => "WIN10", :screenrecorder => true, :build => "testbuild", :name => "testname" } client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 480 driver = Selenium::WebDriver.for( :remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :http_client => client, :desired_capabilities => caps) driver.navigate.to "https://www.google.com" element = driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit puts driver.title driver.quit #### PHP "chrome", 'version' => "latest-1", 'platform' => "WIN10", 'screenrecorder' => true, 'build' => "testbuild", 'name' => "testname" ); $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", $capabilities, 240000 ); $web_driver->get("https://google.com"); $element = $web_driver->findElement(WebDriverBy::name("q")); if($element) { $element->sendKeys("TestingBot"); $element->submit(); } print $web_driver->getTitle(); $web_driver->quit(); ?> #### Java import org.openqa.selenium.By; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; public class JavaSample { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("version", "latest-1"); caps.setCapability("platform", "WIN10"); caps.setCapability("screenrecorder", true); caps.setCapability("build", "testbuild"); caps.setCapability("name", "testname"); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("https://www.google.com/ncr"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); System.out.println(driver.getTitle()); driver.quit(); } } #### Python import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class TestTestingBotClient(unittest.TestCase): def setUp(self): desired_cap = { 'browserName': 'chrome', 'version': 'latest-1', 'platform': 'WIN10', 'screenrecorder': True, 'build': 'testbuild', 'name' : 'testname', } self.driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) def test_google_example(self): self.driver.get("https://www.google.com") if not "Google" in self.driver.title: raise Exception("Unable to load google page!") elem = self.driver.find_element_by_name("q") elem.send_keys("TestingBot") elem.submit() def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() #### JavaScript var wd = require('wd'), testingbotKey = "api_key", testingbotSecret = "api_secret" desiredCaps = { 'browserName': 'chrome', 'version': 'latest-1', 'platform': 'WIN10', 'screenrecorder': true, 'build': 'testbuild', 'name' : 'testname', } driver = wd.remote("https://" + testingbotKey + ":" + testingbotSecret + "@" + "hub.testingbot.com/wd/hub") driver.init(desiredCaps, function() { driver.get('https://www.google.com', function() { driver.title(function(err, title) { console.log(title) driver.quit() }) }) }) #### Ruby #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = { :browserName => "chrome", :browserVersion => "latest-1", :platformName => "WIN10", "tb:options" => { :screenrecorder => true, :build => "testbuild", :name => "testname", "selenium-version" => "3.11.0" } } client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 480 driver = Selenium::WebDriver.for( :remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :http_client => client, :desired_capabilities => caps) driver.navigate.to "https://www.google.com" element = driver.find_element(:name, 'q') element.send_keys "TestingBot" element.submit puts driver.title driver.quit #### PHP "chrome", 'browserVersion' => "latest-1", 'platformName' => "WIN10", 'tb:options' => array( 'screenrecorder' => true, 'build' => "testbuild", 'name' => "testname", 'selenium-version' => "3.11.0" ) ); $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", $capabilities, 240000 ); $web_driver->get("https://google.com"); $element = $web_driver->findElement(WebDriverBy::name("q")); if($element) { $element->sendKeys("TestingBot"); $element->submit(); } print $web_driver->getTitle(); $web_driver->quit(); ?> #### Java import org.openqa.selenium.By; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.MutableCapabilities; import java.net.URL; public class JavaSample { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { MutableCapabilities tbOpts = new MutableCapabilities(); tbOpts.setCapability("screenrecorder", true); tbOpts.setCapability("build", "testbuild"); tbOpts.setCapability("name", "testname"); tbOpts.setCapability("selenium-version", "3.11.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("browserVersion", "latest-1"); caps.setCapability("platformName", "WIN10"); caps.setCapability("tb:options", tbOpts); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("https://www.google.com/ncr"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); System.out.println(driver.getTitle()); driver.quit(); } } #### Python import unittest import sys from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from testingbotclient import TestingBotClient class TestTestingBotClient(unittest.TestCase): def setUp(self): desired_cap = { 'browserName': 'chrome', 'browserVersion': 'latest-1', 'platformName': 'WIN10', 'tb:options' : { 'screenrecorder': True, 'build': 'testbuild', 'name' : 'testname', 'selenium-version' : '3.11.0' } } self.driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) def test_google_example(self): self.driver.get("https://www.google.com") if not "Google" in self.driver.title: raise Exception("Unable to load google page!") elem = self.driver.find_element_by_name("q") elem.send_keys("TestingBot") elem.submit() def tearDown(self): self.driver.quit() status = sys.exc_info() == (None, None, None) tb_client = TestingBotClient('key', 'secret') tb_client.tests.update_test(self.driver.session_id, self._testMethodName, status) if __name__ == ' __main__': unittest.main() #### JavaScript var wd = require('wd'), testingbotKey = "api_key", testingbotSecret = "api_secret" desiredCaps = { 'browserName': 'chrome', 'browserVersion': 'latest-1', 'platformName': 'WIN10', 'tb:options' : { 'screenrecorder': true, 'build': 'testbuild', 'name' : 'testname', 'selenium-version' : '3.11.0' } } driver = wd.remote("https://" + testingbotKey + ":" + testingbotSecret + "@" + "hub.testingbot.com/wd/hub") driver.init(desiredCaps, function() { driver.get('https://www.google.com', function() { driver.title(function(err, title) { console.log(title) driver.quit() }) }) }) ## New Selenium 4 Features Below are some of the new features introduced by Selenium 4 which you can use in your TestingBot tests. ### New Window Create or switch to a new (blank) tab or window. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.switch_to.new_window(:window) @driver.manage.window.position = Selenium::WebDriver::Point.new(200, 400) @driver.switch_to.new_window(:tab) driver.switchTo().newWindow(WindowType.WINDOW); driver.manage().window().setPosition(new Point(200, 400)); driver.switchTo().newWindow(WindowType.TAB); driver.switch_to.new_window('window') driver.set_window_position(200, 400) driver.switch_to.new_window('tab') Driver.SwitchTo().NewWindow(WindowType.Window); Driver.Manage().Window.Position = new Point(200, 400); Driver.SwitchTo().NewWindow(WindowType.Tab); ### Print Page Print the current page as a `PDF`, available in Chrome, Edge and Firefox. You can pass additional options to customize the `PDF`, such as `page size`, `range`, `margins`, `background` and shrink to fit. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) driver.navigate.to url_for("https://testingbot.com") path = "PrintPage.pdf" driver.save_print_page path Path printPage = Paths.get(directory + "PrintPage.pdf"); Pdf print = driver.print(new PrintOptions()); Files.write(printPage, OutputType.BYTES.convertFromBase64Png(print.getContent())); headless_driver.get("https://testingbot.com") pdf = b64decode(headless_driver.print_page()) with open("print_page.pdf", 'wb') as f: f.write(pdf) Driver.Navigate().GoToUrl("https://testingbot.com"); var parentFullName = Directory.GetParent(Environment.CurrentDirectory)?.Parent?.Parent?.FullName; ((ISupportsPrint) Driver).Print(new PrintOptions()).SaveAsFile(parentFullName + "/PrintPage.pdf"); For Chrome and Edge, you need to use `headless` mode to print pages. ### Relative Locators With Relative Locators, you can identify DOM elements in relationship to other DOM elements. You can use a more natural syntax such as: - above - below - left of - right of - near [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.get("https://testingbot.com") element = @driver.find_element(relative: {tag_name: 'div', left: {id: 'outer-orbit'}, below: {id: 'circle-orbit-container'}}) driver.get("https://testingbot.com"); WebElement element = driver.findElement(with(By.tagName("div")) .toLeftOf(By.id("outer-orbit")) .below(By.id("circle-orbit-container"))); driver.get('https://testingbot.com') element = driver.find_elements(locate_with(By.TAG_NAME, "div") .to_left_of({By.ID: "outer-orbit"}) .below({By.ID: "circle-orbit-container"}))[0] Driver.Navigate().GoToUrl("https://testingbot.com"); IWebElement element = Driver.FindElement(RelativeBy.WithLocator(By.TagName("div")) .LeftOf(By.Id("outer-orbit")) .Below(By.Id("circle-orbit-container"))); ### Retrieve Timeouts Selenium 4 now allows you to query the driver for the current timeout values. Please see the examples below on how to do this, for example with implicit waits, pageload timeouts or script timeout. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.manage.timeouts.implicit_wait = 1 p @driver.manage.timeouts.implicit_wait p @driver.manage.timeouts.page_load p @driver.manage.timeouts.script WebDriver.Timeouts timeouts = driver.manage().timeouts(); timeouts.pageLoadTimeout(Duration.ofSeconds(10)); timeouts.implicitlyWait(Duration.ofMillis(11)); timeouts.scriptTimeout(Duration.ofSeconds(12)); timeouts.getPageLoadTimeout(); Assertions.assertEquals(Duration.ofSeconds(10), timeouts.getPageLoadTimeout()); Assertions.assertEquals(Duration.ofMillis(11), timeouts.getImplicitWaitTimeout()); Assertions.assertEquals(Duration.ofSeconds(12), timeouts.getScriptTimeout()); timeouts = Timeouts() timeouts.implicit_wait = 1 driver.timeouts = timeouts assert driver.timeouts.implicit_wait == 1 assert driver.timeouts.page_load == 20 assert driver.timeouts.script == 20 Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0.4); Assert.AreEqual(TimeSpan.FromSeconds(0.4), Driver.Manage().Timeouts().ImplicitWait); Assert.AreEqual(TimeSpan.FromSeconds(4), Driver.Manage().Timeouts().PageLoad); Assert.AreEqual(TimeSpan.FromSeconds(40), Driver.Manage().Timeouts().AsynchronousJavaScript); ### Full Page Screenshots Firefox Only Firefox implemented a feature to take screenshots of the entire page, not just the viewport, which is the default setting for other browsers or for Selenium 3. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.get('https://testingbot.com') @driver.save_screenshot('FullScreenshotOnFirefox.png', full_page: true) WebDriver augmentedDriver = new Augmenter().augment(driver); File file = ((HasFullPageScreenshot) augmentedDriver).getFullPageScreenshotAs(OutputType.FILE); Path fullPageScreenshot = Paths.get(directory + "FullScreenshotOnFirefox.png"); Files.move(file.toPath(), fullPageScreenshot); IHasCommandExecutor hasCommandExecutor = Driver as IHasCommandExecutor; var addFullPageScreenshotCommandInfo = new HttpCommandInfo(HttpCommandInfo.GetCommand, "/session/{sessionId}/moz/screenshot/full"); hasCommandExecutor.CommandExecutor.TryAddCommand("fullPageScreenshot", addFullPageScreenshotCommandInfo); SessionId sessionId = ((RemoteWebDriver)Driver).SessionId; var fullPageScreenshotCommand = new Command(sessionId, "fullPageScreenshot", null); Driver.Navigate().GoToUrl("https://testingbot.com"); var screenshotResponse = hasCommandExecutor.CommandExecutor.Execute(fullPageScreenshotCommand); string base64 = screenshotResponse.Value.ToString(); Screenshot image = new Screenshot(base64); var parentFullName = Directory.GetParent(Environment.CurrentDirectory)?.Parent?.Parent?.FullName; image.SaveAsFile(parentFullName + "/FullScreenshotOnFirefox.png", ScreenshotImageFormat.Png); ### Network Conditions Chrome and Edge only Selenium 4 offers the possibility to modify network conditions for your tests, such as: - Setting latency - Modifying upstream/downstream throughput - Going into offline mode [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.network_conditions = {offline: true, latency: 1, throughput: 10000} WebDriver augmentedDriver = new Augmenter().augment(driver); ChromiumNetworkConditions networkConditions = new ChromiumNetworkConditions(); networkConditions.setOffline(true); ((HasNetworkConditions) augmentedDriver).setNetworkConditions(networkConditions); try { driver.get("https://testingbot.com"); } catch (WebDriverException ex) { ((HasNetworkConditions) augmentedDriver).setNetworkConditions(new ChromiumNetworkConditions()); } TestingBot has been offering [throtteling, mocking and intercepting](https://testingbot.com/support/web-automate/selenium/network) network requests before Selenium 4. ### Change Preferences During Session Firefox only Before Selenium 4, it was only possible to set preferences (through capabilities) at the start of a test. Firefox now provides the option to change preferences during a session. You can do this by toggling the context between `chrome` and `content`. Make sure to switch back to the correct context, or some commands might fail. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[C#](https://testingbot.com#) @driver.get("https://www.google.com") language = @driver.find_element(id: "gws-output-pages-elements-homepage_additional_languages__als") p language @driver.context = 'chrome' @driver.execute_script("Services.prefs.setStringPref('intl.accept_languages', 'es-ES')") @driver.context = 'content' @driver.navigate.refresh language = @driver.find_element(id: "gws-output-pages-elements-homepage_additional_languages__als") p language @driver.quit driver.get("https://www.google.com"); String lang1 = driver.findElement(By.id("gws-output-pages-elements-homepage_additional_languages__als")).getText(); Assertions.assertTrue(lang1.contains("offered in")); WebDriver augmentedDriver = new Augmenter().augment(driver); ((HasContext) augmentedDriver).setContext(FirefoxCommandContext.CHROME); ((JavascriptExecutor) driver).executeScript("Services.prefs.setStringPref('intl.accept_languages', 'es-ES')"); ((HasContext) augmentedDriver).setContext(FirefoxCommandContext.CONTENT); driver.navigate().refresh(); String lang2 = driver.findElement(By.id("gws-output-pages-elements-homepage_additional_languages__als")).getText(); Assertions.assertTrue(lang2.contains("Ofrecido por")); This feature is not yet supported in the Python bindings. IHasCommandExecutor hasCommandExecutor = Driver as IHasCommandExecutor; var getContextCommandInfo = new HttpCommandInfo(HttpCommandInfo.GetCommand, "/session/{sessionId}/moz/context"); var setContextCommandInfo = new HttpCommandInfo(HttpCommandInfo.PostCommand, "/session/{sessionId}/moz/context"); hasCommandExecutor.CommandExecutor.TryAddCommand("getContext", getContextCommandInfo); hasCommandExecutor.CommandExecutor.TryAddCommand("setContext", setContextCommandInfo); SessionId sessionId = ((RemoteWebDriver)Driver).SessionId; Driver.Navigate().GoToUrl("https://www.google.com"); var element = Driver.FindElement(By.CssSelector("#gws-output-pages-elements-homepage_additional_languages__als")); Assert.IsTrue(element.Text.Contains("offered in")); try { Driver.ExecuteJavaScript("Services.prefs.setStringPref('intl.accept_languages', 'es-ES')"); Assert.Fail("Can not change Service prefs in content context, so previous method should fail"); } catch (WebDriverException) { // This is expected } var getContextCommand = new Command(sessionId, "getContext", null); Response response = hasCommandExecutor.CommandExecutor.Execute(getContextCommand); Assert.AreEqual("content", response.Value); Dictionary payload = new Dictionary(); payload.Add("context", "chrome"); var setContextCommand = new Command(sessionId, "setContext", payload); hasCommandExecutor.CommandExecutor.Execute(setContextCommand); response = hasCommandExecutor.CommandExecutor.Execute(getContextCommand); Assert.AreEqual("chrome", response.Value); Driver.ExecuteJavaScript("Services.prefs.setStringPref('intl.accept_languages', 'es-ES')"); try { Driver.Navigate().Refresh(); Assert.Fail("Can not navigate in chrome context, so previous method should fail"); } catch (WebDriverException) { // This is expected } payload.Remove("context"); payload.Add("context", "content"); setContextCommand = new Command(sessionId, "setContext", payload); hasCommandExecutor.CommandExecutor.Execute(setContextCommand); Driver.Navigate().Refresh(); element = Driver.FindElement(By.CssSelector("#gws-output-pages-elements-homepage_additional_languages__als")); Assert.IsTrue(element.Text.Contains("Ofrecido por")); ### BiDirectional Functionality The [WebDriver BiDirectional Protocol](https://testingbot.com/support/web-automate/selenium/selenium-bidi) is a new protocol enhancement that should improve the speed and reliability of Webdriver tests. Its mechanism is similar to CDP (Chrome DevTools Protocol), but is implemented as a vendor agnostic protocol. TestingBot supports [WebDriver BiDi](https://testingbot.com/support/web-automate/selenium/selenium-bidi). Please see the [BiDi documentation examples](https://testingbot.com/support/web-automate/selenium/selenium-bidi) to get started. ## Upgrading dependencies Please see the examples below on how to upgrade to Selenium 4. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[Java](https://testingbot.com#)[JavaScript](https://testingbot.com#)[C#](https://testingbot.com#) gem 'selenium-webdriver', '~> 4.0.0' org.seleniumhq.selenium selenium-java 4.0.0 You can run `npm install selenium-webdriver` to install the latest version, or create/modify your `package.json` file: { "name": "selenium-tests", "version": "1.0.0", "dependencies": { "selenium-webdriver": "^4.0.0" } } pip install selenium==4.0.0 PM> Install-Package Selenium.WebDriver -Version 4.0.0 ## Deprecation Messages and Errors Below is a list of potential errors or deprecation messages you might see when upgrading to Selenium 4. ### AddAdditionalOption The `AddAdditionalCapability` capability is deprecated in Selenium 4, it has been replaced by `AddAdditionalOption`. [Legacy](https://testingbot.com#)[Selenium 4](https://testingbot.com#) var browserOptions = new ChromeOptions(); browserOptions.PlatformName = "Windows 10"; browserOptions.BrowserVersion = "latest"; var tbOptions = new Dictionary(); browserOptions.AddAdditionalCapability("tb:options", tbOptions, true); var browserOptions = new ChromeOptions(); browserOptions.PlatformName = "Windows 10"; browserOptions.BrowserVersion = "latest"; var tbOptions = new Dictionary(); browserOptions.AddAdditionalOption("tb:options", tbOptions); ### Timeout Parameters The parameters passed to `Timeout` functions have switched from long (`TimeUnit`) to duration (`Duration`). [Legacy](https://testingbot.com#)[Selenium 4](https://testingbot.com#) driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.manage().timeouts().setScriptTimeout(4, TimeUnit.MINUTES); driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(4)); driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(5)); ### Wait Parameters `WebDriverWait`, `withTimeout` and `pollingEvery` now expect `Duration` instead of a long time. [Legacy](https://testingbot.com#)[Selenium 4](https://testingbot.com#) new WebDriverWait(driver, 3) .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id"))); Wait wait = new FluentWait(driver) .withTimeout(30, TimeUnit.SECONDS) .pollingEvery(5, TimeUnit.SECONDS) .ignoring(NoSuchElementException.class); new WebDriverWait(driver, Duration.ofSeconds(3)) .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id"))); Wait wait = new FluentWait(driver) .withTimeout(Duration.ofSeconds(30)) .pollingEvery(Duration.ofSeconds(5)) .ignoring(NoSuchElementException.class); ### Merging Capabilities Before Selenium 4 you could merge capabilities, mutating the calling object. Since Selenium 4 this is deprecated, you now need to manually assign the result of the merge operation. [Legacy](https://testingbot.com#)[Selenium 4](https://testingbot.com#) MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("platformVersion", "Windows 10"); FirefoxOptions options = new FirefoxOptions(); options.setHeadless(true); options.merge(capabilities); MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("platformVersion", "Windows 10"); FirefoxOptions options = new FirefoxOptions(); options.setHeadless(true); options = options.merge(capabilities); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/selenium-bidi # Learn about event-driven testing with Selenium BiDi [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) is a new protocol, standardized by the W3C. Even though it's still in draft mode, [support for this new protocol](https://wpt.fyi/results/webdriver/tests/bidi?label=master&label=stable&aligned) has already been implemented in Chrome, Microsoft Edge and Firefox The advantage of using this new protocol (based on WebSocket) over the older one (HTTP) is that it allows for **bidi** rectional communication between the test script and the Selenium endpoint. This means your test scripts can now listen for certain events, generated by the (remote) browser under test. Previously, a similar protocol was developed called [CDP](https://www.selenium.dev/documentation/webdriver/bidi/cdp/) ( **C** hrome **D** evTools **P** rotocol), which only supported Chromium-based browsers (Chrome and Microsoft Edge). The new BiDi protocol is the new official standards-based alternative to CDP. It is supported on multiple browsers and is used for automation with [Puppeteer](https://testingbot.com/support/web-automate/puppeteer). ## Key Features of WebDriver BiDi Protocol There are various advantages to using Selenium BiDi: - **Event-Driven Automation:** Allows your test scripts to listen to browser based events as they happen. This eliminates the need for polling and improves the overall test performance. - **Standardization:** The WebDriver BiDi protocol is a W3C standard, which means you'll get the same consistency and interoperability between browser flavors. You can run the same BiDi test script on multiple different browsers on the TestingBot browser grid. - **Future Proof:** The most popular browser vendors are committed to supporting the WebDriver BiDi Protocol. By adopting BiDi early on, you are future-proofing your test cases and ensuring compatibility with upcoming browser advancements. - **Cross-Browser Compatibility** Unlike CDP, which is restricted to a limited set of browsers, the WebDriver BiDi Protocol is designed to operate across various browsers, including Firefox. ## Configuring Selenium BiDi To get started with Selenium BiDi on TestingBot, you'll need to add several capabilities to your existing Selenium tests: ### Selenium Version 4 is required Selenium BiDi is only available on Selenium 4. We suggest using Selenium version `4.23.0` or higher. Please specify the `selenium-version` capability in a `tb:options` capability. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "tb:options" => { "selenium-version" : '4.33.0' } } options.web_socket_url = true ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("selenium-version", "4.33.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('tb:options', array( 'selenium-version' => '4.33.0' )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'selenium-version': '4.33.0' } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', "goog:chromeOptions" : { "w3c" : true }, "tb:options": { "key": "api_key", "secret": "api_secret", "selenium-version": '4.33.0' } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseSpecCompliantProtocol = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["selenium-version"] = "4.33.0" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ### webSocketUrl capability Please specify the `webSocketUrl` capability to indicate to Selenium that you want to use the BiDi protocol. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) caps = { platformName: "Windows 10", browserName: "chrome", browserVersion: "latest", "selenium-version": "4.33.0", webSocketUrl: true } options.web_socket_url = true ChromeOptions chromeOpts = new ChromeOptions(); chromeOpts.setExperimentalOption("w3c", true); MutableCapabilities tbOptions = new MutableCapabilities(); tbOptions.setCapability("key", "api_key"); tbOptions.setCapability("secret", "api_secret"); tbOptions.setCapability("selenium-version", "4.33.0"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(ChromeOptions.CAPABILITY, chromeOpts); caps.setCapability("platformName", "Windows 10"); caps.setCapability("webSocketUrl", true); caps.setCapability("tb:options", tbOptions); caps.setCapability("browserName", "chrome"); $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setPlatform('Windows 10'); $capabilities->setCapability('webSocketUrl', true); $capabilities->setCapability('tb:options', array( 'selenium-version' => '4.33.0' )); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); tbOptions = { 'name': 'W3C Sample', 'selenium-version': '4.33.0' } chromeOpts = { 'browserName': "chrome", 'platformName': "Windows 10", 'webSocketUrl': True, 'goog:chromeOptions': {'w3c': True}, 'tb:options': tbOptions } self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts) driver = await new webdriver.Builder().withCapabilities({ "browserName": 'chrome', "platformName": 'Windows 10', "goog:chromeOptions" : { "w3c" : true }, "webSocketUrl": true, "tb:options": { "key": "api_key", "secret": "api_secret", "selenium-version": '4.33.0' } }).usingServer("https://hub.testingbot.com/wd/hub").build(); var chromeOptions = new ChromeOptions() { BrowserVersion = "latest", PlatformName = "Windows 10", UseWebSocketUrl = true }; var tbOptions = new Dictionary { ["key"] = "api_key", ["secret"] = "api_secret", ["selenium-version"] = "4.33.0" }; chromeOptions.AddAdditionalCapability("tb:options", tbOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub"), chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); ## Listen to console.log events This example shows how to use Selenium BiDi to collect events generated by the browser in realtime, such as the `console.log` events. It will navigate to a website and click a button that generates `console.log` entries. [Java](https://testingbot.com#)[Python](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#) require "rubygems" require "selenium-webdriver" tb_options = { "name" => "My Bidi Test", "browserName" => "chrome", "platform" => "WIN10", "version" => "latest", "selenium-version" => "4.33.0" } options = Selenium::WebDriver::Chrome::Options.new options.add_option('tb:options', tb_options) options.web_socket_url = true driver = Selenium::WebDriver.for( :remote, :url => "https://key:secret@hub.testingbot.com/wd/hub", :capabilities => options) driver.navigate.to "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" driver.script.add_console_message_handler { |log| puts log } wait = Selenium::WebDriver::Wait.new(timeout: 10) consoleLog = wait.until { element = driver.find_element(id: 'consoleLog') element if element.displayed? } consoleLog.click driver.quit import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.module.LogInspector; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; public class ListenToConsoleLogs { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; static Boolean success = false; public static void main(String[] args) throws MalformedURLException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("webSocketUrl", true); HashMap testingbotOptions = new HashMap<>(); testingbotOptions.put("selenium-version", "4.33.0"); capabilities.setCapability("tb:options", testingbotOptions); WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities); try { Augmenter augmenter = new Augmenter(); driver = augmenter.augment(driver); try (LogInspector logInspector = new LogInspector(driver)) { logInspector.onConsoleEntry(consoleLogEntry -> { System.out.println("text: " + consoleLogEntry.getText()); System.out.println("level: " + consoleLogEntry.getLevel()); success = true; }); String page = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"; driver.get(page); driver.findElement(By.id("consoleLog")).click(); if (success) { markTestStatus(true, "Console logs streaming", driver); } else { markTestStatus(false, "Console logs did not stream", driver); } driver.quit(); } } catch (Exception e) { markTestStatus(false, "Exception!", driver); e.printStackTrace(); driver.quit(); } } public static void markTestStatus(Boolean status, String reason, WebDriver driver) { TestingbotREST r = new TestingbotREST("key", "secret"); Map data = new HashMap(); data.put("success", "1"); data.put("name", "My Test"); r.updateTest(driver.getSessionId(), data); } } from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def console_log(): tb_options = { 'name': 'TestingBot Sample Test', 'webSocketUrl': True, 'selenium-version': '4.33.0' } options = webdriver.ChromeOptions() options.browser_version = 'latest' options.platform_name = 'Windows 10' options.enable_bidi = True options.set_capability('tb:options', tb_options) driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', options=options) driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html') log_entries = [] driver.script.add_console_message_handler(log_entries.append) driver.find_element(By.ID, "consoleLog").click() WebDriverWait(driver, 5).until(lambda _: log_entries) print(log_entries[0].text) driver.quit() const webdriver = require('selenium-webdriver'); const USERNAME = process.env.TB_KEY; const ACCESS_KEY = process.env.TB_SECRET; (async () => { const driver = await (new webdriver.Builder() .withCapabilities({ browserName: 'chrome', platformName: 'WIN10', webSocketUrl: true, 'tb:options': { 'selenium-version': '4.33.0' }, }) .usingServer( `https://${USERNAME}:${ACCESS_KEY}@hub.testingbot.com/wd/hub` ) .build()); // Add a listener for log events. await driver.script().addConsoleMessageHandler((logEntry) => { console.log(logEntry.text); }); await driver.get( 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html' ); // Trigger a console log on the demo page. await driver.findElement({ id: 'consoleLog' }).click(); await driver.quit(); })(); using System.Net.WebSockets; using System.Text.Json; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.BiDi; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "latest", "Windows 10")] [Category("BiDi")] public class BidiTest { private IWebDriver _driver; private CancellationToken _token = CancellationToken.None; private readonly string _browser; private readonly string _version; private readonly string _os; public BidiTest(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true } var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(60) ); } [Test] public async Task CaptureConsoleLogs() { _driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); var bidi = await _driver.AsBiDiAsync(); await bidi.Log.OnEntryAddedAsync(e => Console.WriteLine(e)); _driver.FindElement(By.Id("jsException")).Click(); System.Threading.Thread.Sleep(4000); } [TearDown] public void TearDown() { if (_driver == null) return; var testPassed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { ((IJavaScriptExecutor)_driver).ExecuteScript($"tb:test-result={testPassed.ToString().ToLower()}"); } catch (Exception ex) { TestContext.Out.WriteLine($"Failed to report test result: {ex.Message}"); } finally { _driver.Quit(); _driver.Dispose(); } } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "4.33.0" }; } } } ## Listen to JavaScript Exceptions You can use this API to listen for JavaScript exceptions and register callbacks in your test, to process the exception details. These exception details can help in further inspecting the cause of a failing test. The example test script below will navigate to a web page and click a button that will throw an exception. Selenium BiDi will forward this to your test script. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[CSharp](https://testingbot.com#) require "rubygems" require "selenium-webdriver" tb_options = { "name" => "My Bidi Test", "browserName" => "chrome", "platform" => "WIN10", "version" => "latest", "selenium-version" => "4.33.0" } options = Selenium::WebDriver::Chrome::Options.new options.add_option('tb:options', tb_options) options.web_socket_url = true driver = Selenium::WebDriver.for( :remote, :url => "https://key:secret@hub.testingbot.com/wd/hub", :capabilities => options) driver.navigate.to "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html" driver.script.add_console_message_handler { |log| puts log } wait = Selenium::WebDriver::Wait.new(timeout: 10) consoleLog = wait.until { element = driver.find_element(id: 'consoleLog') element if element.displayed? } consoleLog.click driver.quit import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.module.LogInspector; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; public class ListenToConsoleLogs { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; static Boolean success = false; public static void main(String[] args) throws MalformedURLException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("webSocketUrl", true); HashMap testingbotOptions = new HashMap<>(); testingbotOptions.put("selenium-version", "4.33.0"); capabilities.setCapability("tb:options", testingbotOptions); WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities); try { Augmenter augmenter = new Augmenter(); driver = augmenter.augment(driver); try (LogInspector logInspector = new LogInspector(driver)) { logInspector.onJavaScriptException(logEntry -> { System.out.println("text: " + logEntry.getText()); System.out.println("level: " + logEntry.getLevel()); success = true; }); String page = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"; driver.get(page); driver.findElement(By.id("jsException")).click(); Thread.sleep(1500); if (success) { markTestStatus(true, "Caught a JS exception successfully", driver); } else { markTestStatus(false, "Failed to catch the JS exception", driver); } driver.quit(); } } catch (Exception e) { markTestStatus(false, "Exception!", driver); e.printStackTrace(); driver.quit(); } } public static void markTestStatus(Boolean status, String reason, WebDriver driver) { TestingbotREST r = new TestingbotREST("key", "secret"); Map data = new HashMap(); data.put("success", "1"); data.put("name", "My Test"); r.updateTest(driver.getSessionId(), data); } } from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait def console_log(): tb_options = { 'name': 'TestingBot Sample Test', 'webSocketUrl': True, 'selenium-version': '4.33.0' } options = webdriver.ChromeOptions() options.browser_version = 'latest' options.platform_name = 'Windows 10' options.enable_bidi = True options.set_capability('tb:options', tb_options) driver = webdriver.Remote( command_executor='http://key:secret@hub.testingbot.com/wd/hub', options=options) driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html') log_entries = [] driver.script.add_javascript_error_handler(log_entries.append) driver.find_element(By.ID, "jsException").click() WebDriverWait(driver, 5).until(lambda _: log_entries) print(log_entries[0].text) driver.quit() const webdriver = require('selenium-webdriver'); const USERNAME = process.env.TB_KEY; const ACCESS_KEY = process.env.TB_SECRET; (async () => { const driver = await (new webdriver.Builder() .withCapabilities({ browserName: 'chrome', platformName: 'WIN10', webSocketUrl: true, 'tb:options': { 'selenium-version': '4.33.0' }, }) .usingServer( `https://${USERNAME}:${ACCESS_KEY}@hub.testingbot.com/wd/hub` ) .build()); // Add a listener for error events. await driver.script().addJavaScriptErrorHandler((logEntry) => { console.error(logEntry.text); }); await driver.get( 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html' ); // Trigger a console log on the demo page. await driver.findElement({ id: 'jsException' }).click(); await driver.quit(); })(); using System.Net.WebSockets; using System.Text.Json; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.BiDi; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "latest", "Windows 10")] [Category("BiDi")] public class BidiTest { private IWebDriver _driver; private CancellationToken _token = CancellationToken.None; private readonly string _browser; private readonly string _version; private readonly string _os; public BidiTest(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true } var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(60) ); } [Test] public async Task CaptureConsoleLogs() { _driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); var bidi = await _driver.AsBiDiAsync(); await bidi.Log.OnEntryAddedAsync(e => Console.WriteLine(e)); _driver.FindElement(By.Id("jsException")).Click(); System.Threading.Thread.Sleep(4000); } [TearDown] public void TearDown() { if (_driver == null) return; var testPassed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { ((IJavaScriptExecutor)_driver).ExecuteScript($"tb:test-result={testPassed.ToString().ToLower()}"); } catch (Exception ex) { TestContext.Out.WriteLine($"Failed to report test result: {ex.Message}"); } finally { _driver.Quit(); _driver.Dispose(); } } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "4.33.0" }; } } } ## Intercept Network Request You can intercept and modify network requests with Selenium BiDi. Monitor network traffic, or mock outgoing requests. Modify request details such as headers, body, cookies, method and URL. [Java](https://testingbot.com#)[C#](https://testingbot.com#) import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.module.LogInspector; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; public class ListenToConsoleLogs { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; static Boolean success = false; public static void main(String[] args) throws MalformedURLException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("webSocketUrl", true); HashMap testingbotOptions = new HashMap<>(); testingbotOptions.put("selenium-version", "4.23.0"); capabilities.setCapability("tb:options", testingbotOptions); WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities); try { Augmenter augmenter = new Augmenter(); driver = augmenter.augment(driver); try (Network network = new Network(driver)) { network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT)); CountDownLatch latch = new CountDownLatch(1); network.onBeforeRequestSent( beforeRequestSent -> { network.continueRequest( new ContinueRequestParameters(beforeRequestSent.getRequest().getRequestId())); latch.countDown(); }); driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); boolean countdown = latch.await(5, TimeUnit.SECONDS); if (countdown) { markTestStatus(true, "Network request intercepted successfully", driver); } else { markTestStatus(false, "Network request failed to intercept", driver); } driver.quit(); } } catch (Exception e) { markTestStatus(false, "Exception!", driver); e.printStackTrace(); driver.quit(); } } public static void markTestStatus(Boolean status, String reason, WebDriver driver) { TestingbotREST r = new TestingbotREST("key", "secret"); Map data = new HashMap(); data.put("success", "1"); data.put("name", "My Test"); r.updateTest(driver.getSessionId(), data); } } using System.Net.WebSockets; using System.Text.Json; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.BiDi; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "latest", "Windows 10")] [Category("BiDi")] public class BidiTest { private IWebDriver _driver; private CancellationToken _token = CancellationToken.None; private readonly string _browser; private readonly string _version; private readonly string _os; public BidiTest(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true } var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(60) ); } [Test] public async Task CaptureConsoleLogs() { _driver.Navigate().GoToUrl("https://www.selenium.dev"); var bidi = await _driver.AsBiDiAsync(); await bidi.Network.InterceptRequestAsync(async req => { if (req.Request.Url.EndsWith(".png")) { await req.ProvideResponseAsync(new() { Body = File.ReadAllBytes("smile.png"))) }); } else { await req.ContinueAsync(); } }); } [TearDown] public void TearDown() { if (_driver == null) return; var testPassed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { ((IJavaScriptExecutor)_driver).ExecuteScript($"tb:test-result={testPassed.ToString().ToLower()}"); } catch (Exception ex) { TestContext.Out.WriteLine($"Failed to report test result: {ex.Message}"); } finally { _driver.Quit(); _driver.Dispose(); } } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "4.33.0" }; } } } ## Intercept Network Response You can intercept and modify incoming network responses with Selenium BiDi. Monitor incoming network traffic, or mock incoming requests. Modify request details such as headers, body, cookies, method, URL and status code. [Java](https://testingbot.com#)[C#](https://testingbot.com#) import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.module.LogInspector; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; public class ListenToConsoleLogs { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; static Boolean success = false; public static void main(String[] args) throws MalformedURLException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("webSocketUrl", true); HashMap testingbotOptions = new HashMap<>(); testingbotOptions.put("selenium-version", "4.23.0"); capabilities.setCapability("tb:options", testingbotOptions); WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities); try { Augmenter augmenter = new Augmenter(); driver = augmenter.augment(driver); try (Network network = new Network(driver)) { network.addIntercept(new AddInterceptParameters(InterceptPhase.RESPONSE_STARTED)); CountDownLatch latch = new CountDownLatch(1); network.onResponseStarted( responseDetails -> { network.continueResponse( new ContinueResponseParameters(responseDetails.getRequest().getRequestId())); latch.countDown(); }); network.onResponseStarted( responseDetails -> { network.continueResponse( new ContinueResponseParameters(responseDetails.getRequest().getRequestId())); latch.countDown(); }); driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html"); boolean countdown = latch.await(5, TimeUnit.SECONDS); if (countdown) { markTestStatus(true, "Network request intercepted successfully", driver); } else { markTestStatus(false, "Network request failed to intercept", driver); } driver.quit(); } } catch (Exception e) { markTestStatus(false, "Exception!", driver); e.printStackTrace(); driver.quit(); } } public static void markTestStatus(Boolean status, String reason, WebDriver driver) { TestingbotREST r = new TestingbotREST("key", "secret"); Map data = new HashMap(); data.put("success", "1"); data.put("name", "My Test"); r.updateTest(driver.getSessionId(), data); } } using System.Net.WebSockets; using System.Text.Json; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.BiDi; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "latest", "Windows 10")] [Category("BiDi")] public class BidiTest { private IWebDriver _driver; private CancellationToken _token = CancellationToken.None; private readonly string _browser; private readonly string _version; private readonly string _os; public BidiTest(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = CreateBrowserOptions(); var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(60) ); } [Test] public async Task CaptureNetworkLog() { _driver.Navigate().GoToUrl("https://www.selenium.dev"); var bidi = await _driver.AsBiDiAsync(); await bidi.Network.OnResponseStartedAsync(res => { Console.WriteLine($"URL: {res.Request.Url}"); Console.WriteLine($"Method: {res.Request.Method}"); Console.WriteLine($"Status: {res.Response.Status}"); Console.WriteLine($"Headers: {string.Join(", ", res.Response.Headers.Select(h => $"{h.Name}: {h.Value}"))}"); }); System.Threading.Thread.Sleep(4000); } [TearDown] public void TearDown() { if (_driver == null) return; var testPassed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { ((IJavaScriptExecutor)_driver).ExecuteScript($"tb:test-result={testPassed.ToString().ToLower()}"); } catch (Exception ex) { TestContext.Out.WriteLine($"Failed to report test result: {ex.Message}"); } finally { _driver.Quit(); _driver.Dispose(); } } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "4.27.0" }; } private DriverOptions CreateBrowserOptions() { return _browser.ToLower() switch { "firefox" => new FirefoxOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true }, "safari" => new SafariOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true }, _ => new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true } }; } } } ## Basic Auth By default, Selenium does not support providing an username and password when testing a website behind a Basic Auth protection. The following test example will open a website and enter sample credentials in the basic auth popup window. [Java](https://testingbot.com#)[C#](https://testingbot.com#) import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.bidi.module.LogInspector; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; public class ListenToConsoleLogs { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; static Boolean success = false; public static void main(String[] args) throws MalformedURLException { MutableCapabilities capabilities = new MutableCapabilities(); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("webSocketUrl", true); HashMap testingbotOptions = new HashMap<>(); testingbotOptions.put("selenium-version", "4.23.0"); capabilities.setCapability("tb:options", testingbotOptions); WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities); try (Network network = new Network(driver)) { network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED)); network.onAuthRequired( responseDetails -> network.continueWithAuth( responseDetails.getRequest().getRequestId(), new UsernameAndPassword("foo", "bar"))); driver.get("http://httpbin.org/basic-auth/foo/bar"); String text = driver.findElement(By.tagName("body")).getText(); System.out.println(text); if (text.contains("authenticated")) { markTestStatus(true, "Authentication entered successfully", driver); } else { markTestStatus(false, "Failed to enter authentication credentials", driver); } driver.quit(); } } catch (Exception e) { markTestStatus(false, "Exception!", driver); e.printStackTrace(); driver.quit(); } } public static void markTestStatus(Boolean status, String reason, WebDriver driver) { TestingbotREST r = new TestingbotREST("key", "secret"); Map data = new HashMap(); data.put("success", "1"); data.put("name", "My Test"); r.updateTest(driver.getSessionId(), data); } } using System.Net.WebSockets; using System.Text.Json; using System.Text; using OpenQA.Selenium; using OpenQA.Selenium.BiDi; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Firefox; using OpenQA.Selenium.Safari; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "latest", "Windows 10")] [Category("BiDi")] public class BidiTest { private IWebDriver _driver; private CancellationToken _token = CancellationToken.None; private readonly string _browser; private readonly string _version; private readonly string _os; public BidiTest(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = CreateBrowserOptions(); var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(60) ); } [Test] public async Task CaptureNetworkLog() { _driver.Navigate().GoToUrl("https://www.selenium.dev"); var bidi = await _driver.AsBiDiAsync(); await bidi.Network.OnAuthRequiredAsync(async auth => { if (auth.Request.Url.Contains("httpbin.org/basic-auth")) { await auth.ContinueWithAuthAsync(new UsernameAndPassword("foo", "bar")); } }); await bidi.Network.OnResponseStartedAsync(res => { Console.WriteLine($"URL: {res.Request.Url}"); Console.WriteLine($"Method: {res.Request.Method}"); Console.WriteLine($"Status: {res.Response.Status}"); Console.WriteLine($"Headers: {string.Join(", ", res.Response.Headers.Select(h => $"{h.Name}: {h.Value}"))}"); }); System.Threading.Thread.Sleep(4000); } [TearDown] public void TearDown() { if (_driver == null) return; var testPassed = TestContext.CurrentContext.Result.Outcome.Status == NUnit.Framework.Interfaces.TestStatus.Passed; try { ((IJavaScriptExecutor)_driver).ExecuteScript($"tb:test-result={testPassed.ToString().ToLower()}"); } catch (Exception ex) { TestContext.Out.WriteLine($"Failed to report test result: {ex.Message}"); } finally { _driver.Quit(); _driver.Dispose(); } } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = TestContext.CurrentContext.Test.Name, ["selenium-version"] = "4.27.0" }; } private DriverOptions CreateBrowserOptions() { return _browser.ToLower() switch { "firefox" => new FirefoxOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true }, "safari" => new SafariOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true }, _ => new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true } }; } } } ## Intercept Network Response Using CDP (DevTools) you can intercept network responses generated during the Selenium test. [Java](https://testingbot.com#)[C#](https://testingbot.com#) import org.junit.jupiter.api.*; import org.openqa.selenium.*; import org.openqa.selenium.chrome.*; import org.openqa.selenium.devtools.*; import org.openqa.selenium.devtools.v137.network.Network; import org.openqa.selenium.devtools.v137.network.model.RequestId; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URI; import java.time.Duration; import java.util.Base64; import java.util.HashMap; import java.util.Optional; public class WebDriverDevToolsTest { private RemoteWebDriver driver; private DevTools devTools; @BeforeEach public void setUp() throws Exception { ChromeOptions options = new ChromeOptions(); options.setCapability("browserVersion", "137"); options.setCapability("platformName", "Windows 10"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", System.getenv("TESTINGBOT_KEY")); tbOptions.put("secret", System.getenv("TESTINGBOT_SECRET")); tbOptions.put("name", "DevTools Network Example"); tbOptions.put("selenium-version", "4.33.0"); tbOptions.put("build", "Java-DevTools-" + System.currentTimeMillis()); tbOptions.put("webSocketUrl", true); options.setCapability("tb:options", tbOptions); driver = new RemoteWebDriver( new URI("https://hub.testingbot.com/wd/hub").toURL(), options ); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); devTools = ((HasDevTools) driver).getDevTools(); devTools.createSession(); } @Test public void recordNetworkResponses() { devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty())); devTools.addListener(Network.responseReceived(), response -> { System.out.println("URL: " + response.getResponse().getUrl()); System.out.println("Status: " + response.getResponse().getStatus()); System.out.println("Headers: " + response.getResponse().getHeaders()); RequestId requestId = response.getRequestId(); try { String body = devTools.send(Network.getResponseBody(requestId)).getBody(); boolean isBase64 = devTools.send(Network.getResponseBody(requestId)).getBase64Encoded(); if (isBase64) { body = new String(Base64.getDecoder().decode(body)); } System.out.println("Body: " + body); } catch (Exception e) { System.out.println("Could not fetch response body: " + e.getMessage()); } }); driver.get("https://www.selenium.dev"); try { Thread.sleep(3000); // wait for responses } catch (InterruptedException ignored) {} } @AfterEach public void tearDown() { if (driver != null) { try { ((JavascriptExecutor) driver).executeScript("tb:test-result=true"); } catch (Exception ignored) {} driver.quit(); } } } using System.Collections.Generic; using System.Threading.Tasks; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using OpenQA.Selenium.DevTools; using OpenQA.Selenium.Chrome; using System.Linq; namespace NUnit_TestingBot_Sample { [TestFixture("chrome", "137", "Windows 10")] [Category("DevTools")] public class WebDriverDevtoolsTests { private IWebDriver? _driver; private readonly string _browser; private readonly string _version; private readonly string _os; public WebDriverDevtoolsTests(string browser, string version, string os) { _browser = browser; _version = version; _os = os; } [SetUp] public void SetUp() { var browserOptions = CreateBrowserOptions(); var testingBotOptions = CreateTestingBotOptions(); browserOptions.AddAdditionalOption("tb:options", testingBotOptions); _driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), browserOptions.ToCapabilities(), TimeSpan.FromSeconds(600)); _driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10); } [Test] public async Task RecordNetworkResponse() { INetwork networkInterceptor = _driver!.Manage().Network; networkInterceptor.NetworkResponseReceived += (_, e) => { Console.WriteLine($"Response body: {e.ResponseBody}"); Console.WriteLine($"Response headers: {string.Join(", ", e.ResponseHeaders.Select(h => $"{h.Key}: {h.Value}"))}"); Console.WriteLine($"Response status code: {e.ResponseStatusCode}"); Console.WriteLine($"Response URL: {e.ResponseUrl}"); }; await networkInterceptor.StartMonitoring(); _driver!.Navigate().GoToUrl("https://www.selenium.dev/"); await networkInterceptor.StopMonitoring(); } private ChromeOptions CreateBrowserOptions() { var options = new ChromeOptions { BrowserVersion = _version, PlatformName = _os, UseWebSocketUrl = true }; return options; } [TearDown] public void TearDown() { _driver?.Quit(); _driver?.Dispose(); } private Dictionary CreateTestingBotOptions() { var key = Environment.GetEnvironmentVariable("TESTINGBOT_KEY"); var secret = Environment.GetEnvironmentVariable("TESTINGBOT_SECRET"); if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(secret)) { throw new InvalidOperationException( "TESTINGBOT_KEY and TESTINGBOT_SECRET environment variables must be set"); } return new Dictionary { ["key"] = key, ["secret"] = secret, ["name"] = $"{TestContext.CurrentContext.Test.Name}", ["selenium-version"] = "4.33.0", ["build"] = $"DevTools-Tests-{DateTime.Now:yyyy-MM-dd}" }; } } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/oxygen # Oxygen Automated Browser Testing Oxygen is a powerful Selenium & Appium framework. It comes with a dedicated IDE and supports these features: - Selenese - Page Objects - Record, playback and debug functionality ## Installation You can download the Oxygen IDE from [OxygenHQ](https://oxygenhq.org/). You can download either a Windows, macOS or Linux build, depending on the OS you are using. Once installed, you can configure the IDE to use the TestingBot remote browser grid. ## Configuration You can configure the TestingBot integration in Oxygen IDE by opening the `Settings` window, and navigating to `Cloud Providers`. ![Configuring TestingBot integration with Oxygen IDE](https://testingbot.com/assets/support/oxygen/settings-e6951c9595d5d447512c981daf053e019f3f7e5a1bccbae30c48ff435850f519.png) You can then enable the TestingBot integration. Next, you'll need to fill in the `Key` and `Secret` values. ![Configuring TestingBot credentials with Oxygen IDE](https://testingbot.com/assets/support/oxygen/credentials-f5a6d875eb00f92761383719cdc1952355ca92067d93f4606fb8a101c7cdebee.png) ## Run Test Now you're ready to create your first test. Follow the instructions from the Oxygen IDE/documentation pages, and once you've created your first test, we can run it on a TestingBot browser: ![Run TestingBot test with Oxygen IDE](https://testingbot.com/assets/support/oxygen/run-2557a307b8a1d15e4cd935b2d9c76f755df6a906cb9f4508c54fefc05301a6de.png) ## More Information More information regarding Oxygen IDE is available on the [OxygenHQ website](https://oxygenhq.org/). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/status # Setting Name and Status Each test that you'll run on TestingBot will show up in the [Members Dashboard](https://testingbot.com/members). By default, we do not know what the name of this test is and if it passed or not. To correctly display the test name and status, there are two options: - [use our REST API](https://testingbot.com#api) - [use JavascriptExecutor](https://testingbot.com#javascript) ## TestingBot REST API You can use our [REST API](https://testingbot.com/support/api#updatetest) to update the status and meta-data of a test. The API can be used with any HTTP client, or use one of our [API client libraries](https://testingbot.com/support/api#clients). To use the API, you need the unique identifier of the test that you want to update. Please see [getting the SessionID](https://testingbot.com/support/web-automate/selenium/get-session-id) for more information on how to obtain the sessionID of a specific test. [cURL](https://testingbot.com#)[Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#) curl "https://api.testingbot.com/v1/tests/:webdriver_session_id" \ -X PUT \ -d "test[success]=1" \ -d "test[name]=MyFirstTest" \ -u key:secret require 'testingbot' api = TestingBot::Api.new(key, secret) @api.update_test(webdriver_session_id, { :name => 'MyFirstTest', :success => true }) TestingbotREST restApi = new TestingbotREST(key, secret); boolean success = restApi.updateTest(String webdriver_session_id, Map details); $api = new TestingBot\TestingBotAPI($key, $secret); $api->updateJob($webdriver_session_id, array('name' => 'MyFirstTest', 'success' => true)); import testingbotclient tb = testingbotclient.TestingBotClient(key, secret) testingbotclient.tests.update_test(webdriver_session_id, status_message=.., passed=1|0, build=.., name=..) const TestingBot = require('testingbot-api'); const api = new TestingBot({ api_key: "your-tb-key", api_secret: "your-tb-secret" }); const testData = { "test[success]" : "1", "test[name]" : "MyFirstTest" }; api.updateTest(testData, webdriver_session_id, function(error, testDetails) {}); Arguments: - (string) **id** - a unique string identifying your test (= Selenium sessionId, a UUID) - (boolean) **test[success]** - indicating if the test was successful - (string) **test[status\_message]** - the status/error message of your test - (string) **test[name]** - the name of your test - (string) **test[extra]** - extra data for this test - (string) **groups=...,...** - a comma-separated string of groups for this test - (string) **build=...** - what build this test belongs to ## JavascriptExecutor TestingBot has its own, custom JavascriptExecutor methods that you can call during your test, to change the meta-data of the test that is running. Besides changing the name and status of a test, we offer [other JavascriptExecutor methods](https://testingbot.com/support/web-automate/selenium/annotating-tests#start) as well. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script('tb:test-name=My test') driver.execute_script('tb:test-result=passed') ((JavascriptExecutor)driver).executeScript("tb:test-name=My test"); ((JavascriptExecutor)driver).executeScript("tb:test-result=passed"); $web_driver->executeScript('tb:test-name=My test'); $web_driver->executeScript('tb:test-result=passed'); driver.execute_script('tb:test-name=My test') driver.execute_script('tb:test-result=passed') driver.executeScript('tb:test-name=My test') driver.executeScript('tb:test-result=passed') ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-name=My test"); ((IJavaScriptExecutor)driver).ExecuteScript("tb:test-result=passed"); Arguments: - (string) **id** - a unique string identifying your test (= Selenium sessionId, a UUID) - (boolean) **test[success]** - indicating if the test was successful - (string) **test[status\_message]** - the status/error message of your test - (string) **test[name]** - the name of your test - (string) **test[extra]** - extra data for this test - (string) **groups=...,...** - a comma-separated string of groups for this test - (string) **build=...** - what build this test belongs to Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/debug-tests # Debugging Tests TestingBot provides a range of features that will help you with detecting, debugging and fixing of bugs in your Automated Tests. The type of bugs that your Automated Tests may contain include: - **Incorrect selector** : you are trying to find an element on the page that is no longer there, or has changed its `className`, `id` or `xPath` - **Missing/Incorrect wait condition** : you need to wait for an element to appear, or are using the wrong wait approach - **Timeouts** : perhaps you forgot to close the session at the end of your test (`driver.quit`) - **Other bugs** : various other bugs that might affect your test quality TestingBot provides various tools to help you with these problems: - [Interactive Session](https://testingbot.com#interactive): interact with the VM or device while your test is running - [Video](https://testingbot.com#video): see a video recording of your test - [Logs](https://testingbot.com#logs): a collection of logs is available for each test. ### Interactive Session Our interactive session feature allows you to pause a running Selenium or Appium script, and inspect the remote browser or app with the included Developer Tools. Simply click the **Pause Test** button on the test page while the test is running and you will be navigated to a remote session. You can now use your mouse and keyboard to debug potential issues. ### Video Recording Every test that runs on TestingBot comes with a [recorded video](https://testingbot.com/support/web-automate/selenium/test-options#screenrecorder) of the test session. The video is available in our member area, where you navigate to a test detail page. You can also [fetch the video](https://testingbot.com/support/api#singletest), together with other details, through the TestingBot REST API. ### Log Files For every test that runs on TestingBot, we collect logs generated by the test session. These logs can be useful for pinpointing certain issues with your tests. Log files are available on the test detail pages. You can also [fetch the logs](https://testingbot.com/support/api#singletest), together with other details, through the TestingBot REST API. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/get-session-id # Get Selenium WebDriver SessionID The Selenium WebDriver SessionID is a unique identifier for each of your tests. Usually it's returned in a [UUID format](https://www.w3.org/TR/webdriver/#dfn-generating-a-uuid). You can use this unique identifier for your own purposes, or to use it in combination with the [TestingBot API](https://testingbot.com/support/api). Please see the examples below on how to retrieve the SessionID: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.getSessionId(); const sessionId = await driver.getSession().then(session => session.getId()) Driver.SessionId.ToString(); driver.session_id driver.session_id $web_driver->getSessionID(); ## Using the Selenium SessionID You can use the Selenium SessionID to [mark a test as passed or failed](https://testingbot.com/support/web-automate/selenium/status). You can also use the WebDriver sessionID to link to a test or [share a test](https://testingbot.com/support/other/sharing). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/insecure-certificates # Accepting Insecure Certificates You might want to test a website that does not (yet) have a valid SSL certificate (either it's expired, self-signed, or other). We recommend using our [TestingBot Tunnel](https://testingbot.com/support/tunnel) for this. The Tunnel will automatically convert the invalid certificate to a certificate that all TestingBot VMs and Devices trust. You can also use the `acceptSslCerts` capability, but it does not work as reliable as the TestingBot Tunnel approach. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/proxy # Run tests from behind a proxy If the machine you are using to run tests is behind a proxy, chances are that you won't be able to connect to TestingBot's grid. In this case, you can instruct Selenium to go through your proxy. See the example below. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) ENV['http_proxy'] = 'host:port' //For HTTP System.getProperties().put("http.proxyHost", "..."); System.getProperties().put("http.proxyPort", "..."); System.getProperties().put("http.proxyUser", "..."); System.getProperties().put("http.proxyPassword", "..."); //For HTTPS System.getProperties().put("https.proxyHost", "..."); System.getProperties().put("https.proxyPort", "..."); System.getProperties().put("https.proxyUser", "..."); System.getProperties().put("https.proxyPassword", "..."); $web_driver = RemoteWebDriver::create('https://hub.testingbot.com/wd/hub', $capabilities, null, null, PROXY_URL, PROXY_PORT); open remote_connection.py replace this code: http = urllib3.PoolManager(timeout=self._timeout) with: http = urllib3.ProxyManager('host:port') const driver = new webdriver.Builder(). usingServer('https://hub.testingbot.com/wd/hub'). withCapabilities(capabilities). usingWebDriverProxy("proxy.org:8080"). build(); HttpCommandExecutor commandExecutor = new HttpCommandExecutor(new Uri("https://hub.testingbot.com/wd/hub/"), TimeSpan.FromSeconds(60)); commandExecutor.Proxy = new WebProxy("http://host:port", false); // add caps, for e.g. // ChromeOptions options = new ChromeOptions(); // options.AddAdditionalCapability("browser", "Chrome",true); IWebDriver driver = new RemoteWebDriver(commandExecutor, options.ToCapabilities()); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/screenshots # Taking screenshots During your Automated Testing, you can take screenshots of the current webpage by issuing a "Take Screenshot" command. Depending on which framework/language binding you are using, the syntax might be a little bit different. If you want to automatically take a screenshot for each step in your test, you can use the custom [screenshot TestingBot capability](https://testingbot.com/support/web-automate/selenium/test-options#platform). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.save_screenshot("screenshot.png") driver = (RemoteWebDriver) new Augmenter().augment(driver); File srcFile = (File) ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); FileHandler.copy(srcFile, new File("/location/to/screenshot.png")); file_put_contents('screenshot.png', $web_driver->takeScreenshot()); driver.save_screenshot('screenshot.png') const fs = require('fs') webdriver.WebDriver.prototype.saveScreenshot = function(filename) { return driver.takeScreenshot().then(function(data) { fs.writeFile(filename, data.replace(/^data:image\/png;base64,/,''), 'base64', function(err) { if(err) throw err }) }) } driver.saveScreenshot('screenshot.png') using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace SeleniumTest { public class ScreenShotRemoteWebDriver : RemoteWebDriver, ITakesScreenshot { public ScreenShotRemoteWebDriver(Uri uri, OpenQA.Selenium.Chrome.ChromeOptions dc) : base(uri, dc) { } public new Screenshot GetScreenshot() { Response screenshotResponse = this.Execute(DriverCommand.Screenshot, null); string base64 = screenshotResponse.Value.ToString(); return new Screenshot(base64); } } class Program { static void Main(string[] args) { ScreenShotRemoteWebDriver driver; OpenQA.Selenium.Chrome.ChromeOptions capability = new OpenQA.Selenium.Chrome.ChromeOptions(); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("key", "key", true); capability.AddAdditionalCapability("secret", "secret", true); capability.AddAdditionalCapability("chromeOptions", chromeOptions, true); driver = new ScreenShotRemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub/"), capability ); driver.Navigate().GoToUrl("https://www.google.com/ncr"); Console.WriteLine(driver.Title); IWebElement query = driver.FindElement(By.Name("q")); query.SendKeys("TestingBot"); query.Submit(); Console.WriteLine(driver.Title); ITakesScreenshot screenshotDriver = driver as ITakesScreenshot; Screenshot screenshot = screenshotDriver.GetScreenshot(); screenshot.SaveAsFile("/tmp/screenshot.png", OpenQA.Selenium.ScreenshotImageFormat.Png); driver.Quit(); } } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/sensitive-data # Hiding Sensitive Data When you are running tests on the TestingBot cloud, we automatically gather logs and screenshots/videos of each of your tests. This feature allows testers to debug potential issues with their tests, or verify if their tests are doing what they are supposed to be doing. However, it might be important for you to prevent this logging from happening. For example, you're testing a login/signup page and you are sending a password or secret token. We offer several options to partially or completely disable logging during your tests: - [stripping parameters in logs](https://testingbot.com#params) - [completely disabling logs](https://testingbot.com#disable) - [disable video recordings](https://testingbot.com#video) ## Strip Parameters You can choose to remove all parameters from the TestingBot logs, which are sent during your test. Parameters like passwords, tokens or other sensitive data will no longer appear in our logs. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps["recordLogs"] = "strip-parameters" caps.setCapability("recordLogs", "strip-parameters"); $caps["recordLogs"] = "strip-parameters"; caps["recordLogs"] = "strip-parameters" capabilities['recordLogs'] = 'strip-parameters' caps.SetCapability("recordLogs", "strip-parameters"); ## Disable Logging By default, TestingBot collects several logs during your test. Depending on the browser/platform you're testing on, the log files may include: - **vm** : our logs where we display what the VM is doing, including the Selenium commands it's relaying. - **selenium** : the log file generated by Selenium, which includes parameters and commands your test is sending. - **firefox** : the geckodriver (verbose) log for the test, if the test is running against a Firefox browser. - **sikuli** : if you are using [Sikuli](https://testingbot.com/support/other/sikuli), the output of Sikuli will appear here. - **appium** : mobile tests (live and automated) are using Appium. Commands and parameters will be logged here. - **logcat** : if you are running a mobile app test on Android, we will retrieve the [Android Logcat](https://developer.android.com/studio/command-line/logcat) file. - **android** : this contains the output of the Android emulator. - **browser** : the console logs of the browser. - **cypress** : output generated by Cypress, if you are using [Cypress Testing](https://testingbot.com/support/web-automate/cypress). To **disable all logs** , you can use this capability: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps["recordLogs"] = false caps.setCapability("recordLogs", false); $caps["recordLogs"] = false; caps["recordLogs"] = False capabilities['recordLogs'] = false caps.SetCapability("recordLogs", false); You can also choose to **disable some logs** : [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps["disableLogs"] = ['appium', 'browser'] caps.setCapability("recordLogs", {"appium", "browser"}); $caps["recordLogs"] = array('appium', 'browser'); caps["recordLogs"] = ['appium', 'browser'] capabilities['recordLogs'] = ['appium', 'browser'] caps.SetCapability("recordLogs", {"appium", "browser"}); ## Disable video recordings By default, we'll record the screen during your test. This makes it easy to troubleshoot or verify the test. You can choose to disable the video recording with this capability: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screenrecorder"] = false DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screenrecorder", false); $caps = array( "screenrecorder" => false ); capabilities = { "screenrecorder" : False } const capabilities = { "screenrecorder" : false } DesiredCapabilities caps = new DesiredCapabilities(); caps.SetCapability("screenrecorder", false); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/test-results # Test Results After running a test on TestingBot, you can see the test result in the [TestingBot Dashboard](https://testingbot.com#dashboard) overview. You can click each test to see a [detailed overview](https://testingbot.com#single) for each specific test. ## The Dashboard The dashboard contains an overview of all your previous test runs, together with some meta-data: - **Test Name** : you can pass this name via our [REST API or Javascript Executor](https://testingbot.com/support/web-automate/selenium/status). - **Pass/Failure state** : you can [indicate](https://testingbot.com/support/web-automate/selenium/status) whether this test passed or failed. - **Browser/Device** : the browser or device that was used by the test. TestingBot provides [more than 5000 different browser/device combinations](https://testingbot.com/support/web-automate/browsers). - **Start Date** : when we received the call to start your test. - **Test Duration** : how long it took for your test to run. This is the actual run time, potential queueing time is not included. ## Single Test Detail Page For each test, we have a test detail page, which shows an overview of all the data we have: - Test Name - [sessionID](https://testingbot.com/support/web-automate/selenium/get-session-id) of the test - the pass/failure state - the browser/device that was used by the test - the date when the test started - how long the test took to run - logs for the test - a video recording of the test - the user who started the test in your team - a list of steps, explaining what the test did ## Viewing results without the dashboard You can [share, embed and link to builds or individual tests](https://testingbot.com/support/other/sharing) without having to visit the dashboard. This is useful when you want to create your own reporting. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/browser-window-size # Maximize or resize browser window Selenium WebDriver makes it possible to resize and maximize a browser window during an automated test. Below you'll find examples on how to: - [Maximize a window](https://testingbot.com#maximize) - [Resize a window](https://testingbot.com#resize) ## Maximize a window The example below shows how to maximize the window to the full screen resolution (you can [change the screen resolution](https://testingbot.com/support/web-automate/selenium/change-screen-resolution) as well). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.manage.window.maximize driver.manage().window().maximize(); $web_driver->manage()->window()->maximize(); driver.maximize_window() driver.manage().window().maximize(); driver.Manage().Window.Maximize(); Maximizing a window will only work on desktop browsers, not on mobile. ## Resize a window The example below shows how to resize the current window. If you specify a size larger than the current resolution, elements may appear off-screen. Find out how to [change the screen resolution](https://testingbot.com/support/web-automate/selenium/change-screen-resolution). [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.manage.window.resize_to(1920, 1080) Dimension dimension = new Dimension(1920, 1080); driver.manage().window().setSize(dimension); $web_driver->manage()->window()->setSize(new WebDriverDimension(1920, 1080)); driver.set_window_size(1920, 1080) await driver.manage().window().setRect({ width: 1920, height: 1080 }); driver.Manage().Window.Size = new Size(1920, 1080); Resizing a window will only work on desktop browsers, not on mobile. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/change-screen-resolution # Change desktop screen resolution with Selenium The TestingBot Desktop VMs (Windows, macOS and Linux) all support changing the screen-resolution before a test starts. We currently support the following screen resolutions: Value Type | Default Value | || string | "1280x1024" | Platform | Resolutions || Windows/Linux | - 800x600 - 1024x768 - 1152x864 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1400x1050 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2560x1440 | | macOS | - 800x600 - 1024x768 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1366x768 - 1440x900 - 1600x900 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2048x1536 | | [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) caps = Selenium::WebDriver::Remote::Capabilities.new caps["screen-resolution"] = "1280x1024" DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("screen-resolution", "1280x1024"); $caps = array( "screen-resolution" => "1280x1024" ); capabilities = { "screen-resolution" : "1280x1024" } const capabilities = { "screen-resolution" : "1280x1024" } // For Chrome browser OpenQA.Selenium.Chrome.ChromeOptions chromeCapability = new OpenQA.Selenium.Chrome.ChromeOptions(); capability.AddAdditionalCapability("resolution", "1280x1024", true); // For Edge browser OpenQA.Selenium.Edge.EdgeOptions edgecapability = new OpenQA.Selenium.Edge.EdgeOptions(); capability.AddAdditionalCapability("resolution", "1280x1024"); // For IE browser OpenQA.Selenium.IE.InternetExplorerOptions ieCapability = new OpenQA.Selenium.IE.InternetExplorerOptions(); capability.AddAdditionalCapability("resolution", "1280x1024", true); // For Firefox browser OpenQA.Selenium.Firefox.FirefoxOptions firefoxCapability = new OpenQA.Selenium.Firefox.FirefoxOptions(); capability.AddAdditionalCapability("resolution", "1280x1024", true); // For Safari browser OpenQA.Selenium.Safari.SafariOptions safariCapability = new OpenQA.Selenium.Safari.SafariOptions(); safariCapability.AddAdditionalCapability("resolution", "1280x1024"); // For Opera browser OpenQA.Selenium.Opera.OperaOptions operaCapability = new OpenQA.Selenium.Opera.OperaOptions(); operaCapability.AddAdditionalCapability("resolution", "1280x1024"); The browser window is not maximized when starting a Selenium test. Changing the screen resolution does not maximize browser. See how to [maximize and resize the browser window](https://testingbot.com/support/web-automate/selenium/browser-window-size). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/basic-http-authentication # Basic HTTP Authentication If you are testing a website that is protected with Basic HTTP Authentication, then your automated test might get stuck when opening the URL. You can pass the `username` and `password` in the URL, see the example below: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.navigate.to "https://:@www.example.com/password.html" driver.get("https://:@www.example.com/password.html") $web_driver->get("https://:@www.example.com/password.html"); driver.get("https://:@www.example.com/password.html") driver.get('https://:@www.example.com/password.html').then(function(){ }); driver.Navigate().GoToUrl("https://:@www.example.com/password.html"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/browser-extension # Browser Extension While running Automated tests, you might want to have a browser extension installed. Below you can find information on how to add a browser extension to a Chrome, Firefox, Edge or Safari browser running in the TestingBot cloud. To get started, make sure you have the extension file ready, then upload it either to a public URL or use the [TestingBot Storage](https://testingbot.com#storage). Once you have a URL, you can specify the `load-extension` capability. This will instruct the remote TestingBot browsers to download the extension and add it to the browser at startup. Example: "load-extension" : "https://..." Example (Selenium 4): "tb:options" : { "load-extension" : "https://..." } Browser | Supported Format(s) | Example || [Chrome](https://testingbot.com#chrome) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) - `.crx` file | - `https://.../extension.zip` - `tb://sample-extension` | | [Firefox](https://testingbot.com#firefox) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, `lib/ directory`, ...) - `.xpi` file | - `https://.../extension.zip` - `tb://sample-extension` | | [Edge](https://testingbot.com#edge) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) - `.crx` file | - `https://.../extension.zip` - `tb://sample-extension` | | [Safari & Safari Technology Preview](https://testingbot.com#safari) | - Test (Unsigned) Safari Web/App Extensions bundled in a zip file - `.safariextz` file for Safari \<= 12 | - `https://.../extension.zip` - `tb://sample-extension` | ## TestingBot Storage With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your extensions to the TestingBot servers. The advantage of this is that our test VMs can immediately download your extension from the TestingBot network, which is much faster than downloading from the public internet. The API call will return a unique identifier, similar to `tb://efe932jfk`. You can then use this identifier with the capability: `"load-extension" : "tb://..."` ## Chrome Browser Extension Testing Once you've specified `"load-extension"`, the Chrome browser will start up with the extension preloaded. You can now run your Selenium tests while the extension is active on the remote browser. ### UI Testing Chrome Extensions To test the UI of your Chrome extension, you can have your Selenium test navigate to a `chrome-extension://` URL. For example, if the ID of your addon is `paaamahlcokbnafoiahanekijojkhbdm`, you can navigate to `chrome-extension://paaamahlcokbnafoiahanekijojkhbdm`. Please see the NodeJS example below for a complete rundown on how to test the UI of your Chrome extension: const webdriver = require('selenium-webdriver'); const capabilities = { 'platform' : 'WIN10', 'browserName' : 'chrome', 'version' : 'latest', 'tb:options': { 'load-extension': 'https://...path..to..extension' } } async function runTest () { let driver = new webdriver.Builder() .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); await driver.get('chrome-extension://paaamahlcokbnafoiahanekijojkhbdm/popup/index.html'); const element = await driver.findElement(By.css('#environments')); const isElementDisplayed = await element.isDisplayed(); if (isElementDisplayed) { console.log('Element is present on the page.'); } else { console.log('Element is not present on the page.'); } await driver.quit(); } runTest(); ## Firefox Browser Extension Testing You can specify the URL to a `xpi` file in the `load-extension` capability. This will make sure the Firefox browser has the extension installed (as a temporary extension) at the start of the Selenium test. ### UI Testing Firefox Extensions If you want to test the UI of your Firefox extension, the `moz-extension://` URL, you will need to specify the extension ID in the URL. Because TestingBot installs the extension as a temporary extension, the id will always be different as it is generated as a random uuid(4). TestingBot provides a capability to hardcode your Firefox exension to a fixed uuid which you've generated, by using the `firefoxExtensionMap` capability. To use this, you could set the ID in the `manifest.json` of the extension: "browser_specific_settings": { "gecko": { "id": "addon@testingbot.com", "strict_min_version": "109.0" } } You can now link the gecko id to a uuid you've generated: const webdriver = require('selenium-webdriver'); const capabilities = { 'platform' : 'WIN10', 'browserName' : 'firefox', 'version' : 'latest', 'tb:options': { 'load-extension': 'https://...path..to..extension', 'firefoxExtensionMap': { 'addon@testingbot.com': '3d9b1639-77fb-44a1-888a-6d97d773e96b' } } } async function runTest () { let driver = new webdriver.Builder() .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); await driver.get('moz-extension://3d9b1639-77fb-44a1-888a-6d97d773e96b/popup/index.html'); const element = await driver.findElement(By.css('#environments')); const isElementDisplayed = await element.isDisplayed(); if (isElementDisplayed) { console.log('Element is present on the page.'); } else { console.log('Element is not present on the page.'); } await driver.quit(); } runTest(); ## Edge Browser Extension Testing Once you've specified `"load-extension"`, the Edge browser will start up with the extension preloaded. You can now run your Selenium tests while the extension is active on the remote Edge browser. ### UI Testing Edge Extensions To test the UI of your Edge extension, you can have your Selenium test navigate to a `chrome-extension://` or `extension://` URL. For example, if the ID of your addon is `paaamahlcokbnafoiahanekijojkhbdm`, you can navigate to `extension://paaamahlcokbnafoiahanekijojkhbdm`. Please see the NodeJS example below for a complete rundown on how to test the UI of your Edge extension: const webdriver = require('selenium-webdriver'); const capabilities = { 'platform' : 'WIN10', 'browserName' : 'microsoftedge', 'version' : 'latest', 'tb:options': { 'load-extension': 'https://...path..to..extension' } } async function runTest () { let driver = new webdriver.Builder() .usingServer('https://api_key:api_secret@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); await driver.get('extension://paaamahlcokbnafoiahanekijojkhbdm/popup/index.html'); const element = await driver.findElement(By.css('#environments')); const isElementDisplayed = await element.isDisplayed(); if (isElementDisplayed) { console.log('Element is present on the page.'); } else { console.log('Element is not present on the page.'); } await driver.quit(); } runTest(); ## Safari Extension Testing Safari 16 and higher only TestingBot allows you to upload a zip file containing your (unsigned) Safari Web Extension or Safari App Extension. Simply provide a URL to a zip file containing the extension, or upload the zip file on [TestingBot Storage](https://testingbot.com#storage). You can now specify the URL to this file in the `load-extension` capability. When your test starts on a remote Safari instance, the extension will be enabled by default. TestingBot provides Safari Technology Preview as well, allowing you to test on the upcoming new Safari version. You can use the same extension testing features, simply change the `version` to `dev`. ### Safari Extension Automation TestingBot will automatically install and enable the extension in the Safari browser. Permissions will be granted automatically for the extension to access all webpages during the test. ![Safari permissions](https://testingbot.com/assets/support/web-automate/selenium/browser-extension/permissions-9541cd4aa43649ed64627925d68b08972d5267c39bea3823426fdb88ad7d6e49.png) ### Temporary Extension Installation [Since Safari 18.4](https://webkit.org/blog/16574/webkit-features-in-safari-18-4/#web-extensions) you can temporarily install web extensions, without having to build it with Xcode. You can simply zip your web extension and TestingBot will automatically install it as a temporary extension. You can try it on TestingBot's macOS Sequoia and macOS Tahoe machines. The zip file could contain for example following 4 files: `background.js`, `content.js`, `manifest.json` and `page.js`. ### UI Testing Safari Extensions To test the UI of your Safari extension, you will need to know the `safari-web-extension://` or `safari-app-extension://` URI. As Safari can change this to a random UUID, you will need to use the `tb:getExtensionId` command in your test to determine the correct URI to use. Safaridriver currently contains a bug that does not detect the load completion of a `safari-web-extension://` request. To work around this, set the [pageLoad](https://www.w3.org/TR/webdriver2/#timeouts) timeout to a low value and catch any timeout error. Please see the examples below on how to run a UI test against a Safari Web/App Extension: [Ruby](https://testingbot.com#)[Java](https://testingbot.com#)[Node.js](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "safari" caps["browserVersion"] = "18.0" caps["platformName"] = "SEQUOIA" caps["tb:options"] = { "load-extension": "tb://...safari-extension-path..." } http_client = Selenium::WebDriver::Remote::Http::Default.new http_client.read_timeout = 300 http_client.open_timeout = 300 driver = Selenium::WebDriver.for( :remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :options => caps, :http_client => http_client) driver.navigate.to "http://www.google.com/ncr" driver.manage.timeouts.page_load = 5 extension_id = driver.execute_script("tb:getExtensionId") begin driver.navigate.to "#{extension_id}popup/index.html" rescue => e puts e.message end puts driver.page_source driver.quit import org.openqa.selenium.*; import org.openqa.selenium.remote.*; import java.net.URL; import java.util.*; public class SafariExtensionTest { public static void main(String[] args) throws Exception { MutableCapabilities caps = new MutableCapabilities(); caps.setCapability("browserName", "safari"); caps.setCapability("browserVersion", "18.0"); caps.setCapability("platformName", "SEQUOIA"); Map tbOptions = new HashMap<>(); tbOptions.put("load-extension", "tb://...safari-extension-path..."); caps.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver( new URL("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"), caps ); driver.get("http://www.google.com/ncr"); ((JavascriptExecutor) driver).executeScript("tb:setPageLoadTimeout", 5); String extensionId = (String) ((JavascriptExecutor) driver).executeScript("tb:getExtensionId"); try { driver.get(extensionId + "popup/index.html"); } catch (TimeoutException e) { System.out.println(e.getMessage()); } System.out.println(driver.getPageSource()); driver.quit(); } } const { Builder } = require("selenium-webdriver"); (async () => { let caps = { browserName: "safari", browserVersion: "18.0", platformName: "SEQUOIA", "tb:options": { "load-extension": "tb://...safari-extension-path..." } }; let driver = await new Builder() .usingServer("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub") .withCapabilities(caps) .build(); await driver.get("http://www.google.com/ncr"); await driver.manage().setTimeouts({ pageLoad: 5000 }); const extensionId = await driver.executeScript("tb:getExtensionId"); try { await driver.get(`${extensionId}popup/index.html`); } catch (e) { console.log(e.message); } const pageSource = await driver.getPageSource(); console.log(pageSource); await driver.quit(); })(); from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities caps = { "browserName": "safari", "browserVersion": "18.0", "platformName": "SEQUOIA", "tb:options": { "load-extension": "tb://...safari-extension-path..." } } driver = webdriver.Remote( command_executor="https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", desired_capabilities=caps ) driver.get("http://www.google.com/ncr") driver.set_page_load_timeout(5) extension_id = driver.execute_script("tb:getExtensionId") try: driver.get(f"{extension_id}popup/index.html") except Exception as e: print(e) print(driver.page_source) driver.quit() using OpenQA.Selenium; using OpenQA.Selenium.Remote; using System; using System.Collections.Generic; class SafariExtensionTest { static void Main() { var capabilities = new DesiredCapabilities(); capabilities.SetCapability("browserName", "safari"); capabilities.SetCapability("browserVersion", "18.0"); capabilities.SetCapability("platformName", "SEQUOIA"); capabilities.SetCapability("tb:options", new Dictionary { { "load-extension", "tb://...safari-extension-path..." } }); var driver = new RemoteWebDriver( new Uri("https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"), capabilities ); driver.Navigate().GoToUrl("http://www.google.com/ncr"); driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5); string extensionId = (string)((IJavaScriptExecutor)driver).ExecuteScript("tb:getExtensionId"); try { driver.Navigate().GoToUrl(extensionId + "popup/index.html"); } catch (WebDriverTimeoutException e) { Console.WriteLine(e.Message); } Console.WriteLine(driver.PageSource); driver.Quit(); } } ### Older Safari versions For Safari versions up to Safari 12, you can use a `.safariextz` format, in a `zip` file, to run and test Safari extensions. ## iOS Mobile Safari Browser Extension Testing You can test your iOS Mobile Safari native extension with TestingBot. Simply upload your extension `.ipa` file to [TestingBot Storage](https://testingbot.com/support/api#upload) and use it in your capabilities: { "appium:app": "tb://path-to-mobile-safari-ext-ipa", "tb:realDevice": true, "appium:includeSafariInWebviews": true, "deviceName": "iPhone 16" } Next, you will need to allow this extension through the settings (preferences) app. Finally, we'll switch to the Safari app and change the context to Safari (WEBVIEW). Please see the examples below. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#) require 'appium_lib' caps = { caps: { platformName: 'iOS', automationName: 'XCUITest', 'appium:app' => 'tb://path-to-mobile-safari-ext-ipa', 'tb:realDevice' => true, 'deviceName' => 'iPhone 16', 'appium:includeSafariInWebviews' => true }, appium_lib: { server_url: 'https://hub.testingbot.com/wd/hub' } } driver = Appium::Driver.new(caps, true) driver.start_driver begin # 1. Open Safari settings via deep link driver.execute_script('mobile: deepLink', args: { url: 'app-prefs:com.apple.mobilesafari' }) # 2. Tap "Extensions" extensions = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'Extensions'") extensions.click # 3. Tap your extension extension = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'") extension.click # 4. Enable "Allow Extension" allow_switch = driver.find_element(:predicate, "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'") allow_switch.click # 5. Tap "All Websites" all_sites = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'All Websites'") all_sites.click # 6. Tap "Allow" allow = driver.find_element(:predicate, "type == 'XCUIElementTypeCell' AND name == 'Allow'") allow.click # 7. Terminate Settings app driver.execute_script('mobile: terminateApp', args: { bundleId: 'com.apple.Preferences' }) # 8. Launch Safari driver.execute_script('mobile: launchApp', args: { bundleId: 'com.apple.mobilesafari' }) # 9. Switch to WebView context contexts = driver.available_contexts webview = contexts.find { |ctx| ctx.include?('WEBVIEW') } driver.set_context(webview) if webview puts 'Finished automation steps.' ensure driver.quit_driver end import io.appium.java_client.AppiumBy; import io.appium.java_client.ios.IOSDriver; import io.appium.java_client.remote.IOSMobileCapabilityType; import io.appium.java_client.remote.MobileCapabilityType; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import java.net.URL; import java.util.List; import java.util.Set; public class IOSAppiumAutomation { public static void main(String[] args) { try { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS"); caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, "XCUITest"); caps.setCapability("appium:app", "tb://path-to-mobile-safari-ext-ipa"); caps.setCapability("tb:realDevice", true); caps.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone 16"); caps.setCapability("appium:includeSafariInWebviews", true); IOSDriver driver = new IOSDriver<>( new URL("https://hub.testingbot.com/wd/hub"), caps); // 1. Open Safari Settings via deep link driver.executeScript("mobile: deepLink", java.util.Map.of("url", "app-prefs:com.apple.mobilesafari")); // 2. Tap "Extensions" WebElement extensionsCell = driver.findElement( new AppiumBy.ByIosNsPredicate("type == 'XCUIElementTypeCell' AND name == 'Extensions'")); extensionsCell.click(); // 3. Tap your extension name WebElement extensionItem = driver.findElement( new AppiumBy.ByIosNsPredicate("type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'")); extensionItem.click(); // 4. Toggle "Allow Extension" WebElement allowSwitch = driver.findElement( new AppiumBy.ByIosNsPredicate("type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'")); allowSwitch.click(); // 5. Tap "All Websites" WebElement allWebsites = driver.findElement( new AppiumBy.ByIosNsPredicate("type == 'XCUIElementTypeCell' AND name == 'All Websites'")); allWebsites.click(); // 6. Tap "Allow" WebElement allow = driver.findElement( new AppiumBy.ByIosNsPredicate("type == 'XCUIElementTypeCell' AND name == 'Allow'")); allow.click(); // 7. Terminate Settings driver.executeScript("mobile: terminateApp", java.util.Map.of("bundleId", "com.apple.Preferences")); // 8. Launch Safari driver.executeScript("mobile: launchApp", java.util.Map.of("bundleId", "com.apple.mobilesafari")); // 9. Switch to WebView context Set contexts = driver.getContextHandles(); for (String context : contexts) { if (context.contains("WEBVIEW")) { driver.context(context); break; } } System.out.println("Finished automation steps."); driver.quit(); } catch (Exception e) { e.printStackTrace(); } } } const { remote } = require('webdriverio'); (async () => { const driver = await remote({ path: 'https://hub.testingbot.com/wd/hub', port: 443, capabilities: { 'appium:app': 'tb://path-to-mobile-safari-ext-ipa', platformName: 'iOS', automationName: 'XCUITest', "tb:realDevice": true, "appium:includeSafariInWebviews": true, "deviceName": "iPhone 16" }, }); // 1. Open Safari settings via deep link await driver.execute('mobile: deepLink', { url: 'app-prefs:com.apple.mobilesafari', }); // 2. Tap "Extensions" const extensionsCell = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'Extensions'`); await extensionsCell.waitForExist({ timeout: 10000 }); await extensionsCell.click(); // 3. Tap on your extension (e.g., "webrequest-har-collect") const extensionItem = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'`); await extensionItem.waitForExist({ timeout: 60000 }); await extensionItem.click(); // 4. Enable the switch "Allow Extension" const allowSwitch = await driver.$(`-ios predicate string:type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'`); await allowSwitch.waitForExist({ timeout: 60000 }); await allowSwitch.click(); // 5. Tap "All Websites" const allWebsites = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'All Websites'`); await allWebsites.waitForExist({ timeout: 60000 }); await allWebsites.click(); // 6. Tap "Allow" const allow = await driver.$(`-ios predicate string:type == 'XCUIElementTypeCell' AND name == 'Allow'`); await allow.waitForExist({ timeout: 60000 }); await allow.click(); // 7. Terminate Settings app await driver.execute('mobile: terminateApp', { bundleId: 'com.apple.Preferences', }); // 8. Launch Safari await driver.execute('mobile: launchApp', { bundleId: 'com.apple.mobilesafari', }); // 9. Switch to WebView context const contexts = await driver.getContexts(); const webview = contexts.find(ctx => ctx.includes('WEBVIEW')); if (webview) { await driver.switchContext(webview); } console.log('Finished automation steps.'); await driver.deleteSession(); })(); from appium import webdriver from selenium.webdriver.common.by import By import time caps = { "platformName": "iOS", "automationName": "XCUITest", "appium:app": "tb://path-to-mobile-safari-ext-ipa", "appium:includeSafariInWebviews": True, "deviceName": "iPhone 16", "tb:realDevice": True, } driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', desired_capabilities=caps ) try: # 1. Open Safari settings via deep link driver.execute_script('mobile: deepLink', { 'url': 'app-prefs:com.apple.mobilesafari' }) # 2. Tap "Extensions" extensions_cell = driver.find_element( By.IOS_PREDICATE, "type == 'XCUIElementTypeCell' AND name == 'Extensions'" ) extensions_cell.click() # 3. Tap on your extension (e.g., "webrequest-har-collect") extension_item = driver.find_element( By.IOS_PREDICATE, "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'" ) extension_item.click() # 4. Enable the switch "Allow Extension" allow_switch = driver.find_element( By.IOS_PREDICATE, "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'" ) allow_switch.click() # 5. Tap "All Websites" all_websites = driver.find_element( By.IOS_PREDICATE, "type == 'XCUIElementTypeCell' AND name == 'All Websites'" ) all_websites.click() # 6. Tap "Allow" allow = driver.find_element( By.IOS_PREDICATE, "type == 'XCUIElementTypeCell' AND name == 'Allow'" ) allow.click() # 7. Terminate Settings app driver.execute_script('mobile: terminateApp', { 'bundleId': 'com.apple.Preferences' }) # 8. Launch Safari driver.execute_script('mobile: launchApp', { 'bundleId': 'com.apple.mobilesafari' }) # 9. Switch to WebView context contexts = driver.contexts webview = next((ctx for ctx in contexts if 'WEBVIEW' in ctx), None) if webview: driver.switch_to.context(webview) print("Finished automation steps.") finally: driver.quit() using OpenQA.Selenium; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Enums; using OpenQA.Selenium.Appium.iOS; using System; using System.Linq; using System.Collections.ObjectModel; class Program { static void Main(string[] args) { var options = new AppiumOptions(); options.AddAdditionalCapability(MobileCapabilityType.PlatformName, "iOS"); options.AddAdditionalCapability(MobileCapabilityType.AutomationName, "XCUITest"); options.AddAdditionalCapability("appium:app", "tb://path-to-mobile-safari-ext-ipa"); options.AddAdditionalCapability("tb:realDevice", true); options.AddAdditionalCapability("deviceName", "iPhone 16"); options.AddAdditionalCapability("appium:includeSafariInWebviews", true); var driver = new IOSDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); try { // 1. Open Safari settings via deep link driver.ExecuteScript("mobile: deepLink", new { url = "app-prefs:com.apple.mobilesafari" }); // 2. Tap "Extensions" var extensionsCell = driver.FindElementByIosNsPredicate( "type == 'XCUIElementTypeCell' AND name == 'Extensions'"); extensionsCell.Click(); // 3. Tap extension (e.g., "webrequest-har-collect") var extensionItem = driver.FindElementByIosNsPredicate( "type == 'XCUIElementTypeCell' AND name == 'webrequest-har-collect'"); extensionItem.Click(); // 4. Tap "Allow Extension" switch var allowSwitch = driver.FindElementByIosNsPredicate( "type == 'XCUIElementTypeSwitch' AND name == 'Allow Extension'"); allowSwitch.Click(); // 5. Tap "All Websites" var allWebsites = driver.FindElementByIosNsPredicate( "type == 'XCUIElementTypeCell' AND name == 'All Websites'"); allWebsites.Click(); // 6. Tap "Allow" var allow = driver.FindElementByIosNsPredicate( "type == 'XCUIElementTypeCell' AND name == 'Allow'"); allow.Click(); // 7. Terminate Settings app driver.ExecuteScript("mobile: terminateApp", new { bundleId = "com.apple.Preferences" }); // 8. Launch Safari driver.ExecuteScript("mobile: launchApp", new { bundleId = "com.apple.mobilesafari" }); // 9. Switch to WebView context ReadOnlyCollection contexts = driver.Contexts; string webview = contexts.FirstOrDefault(c => c.Contains("WEBVIEW")); if (webview != null) { driver.Context = webview; } Console.WriteLine("Finished automation steps."); } finally { driver.Quit(); } } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/firefox-profile # Firefox Profile With Selenium WebDriver, it's possible to set a custom [Firefox profile](https://support.mozilla.org/en-US/kb/profile-manager-create-remove-switch-firefox-profiles), which will be used during your automated tests on TestingBot. To change preferences and settings within Firefox, you'll need to instantiate a new `FirefoxProfile` object and update the properties of the profile. ## Change Firefox Profile In the example below, we'll set the `accept language` to Spanish and change the `user-agent` header. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require "rubygems" require "selenium-webdriver" profile = Selenium::WebDriver::Firefox::Profile.new profile["general.useragent.override"] = "Custom-Agent" # Change user-agent profile["intl.accept_languages"] = "es" # Setting accept language to Spanish options = Selenium::WebDriver::Firefox::Options.new(profile: profile) options.browser_version = "latest" options.platform_name = "WIN10" options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'firefox profile example' }) driver = Selenium::WebDriver.for(:remote, :url => "https://hub.testingbot.com/wd/hub", :options => options) FirefoxOptions options = new FirefoxOptions(); FirefoxProfile profile = new FirefoxProfile(); profile.setPreference("general.useragent.override", "Custom-Agent"); // Change user-agent profile.setPreference("intl.accept_languages", "es"); // Setting accept language to Spanish options.setProfile(profile); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); tbOptions.put("name", "firefox profile example"); options.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver(new URL("https://hub.testingbot.com/wd/hub"), options); require_once('vendor/autoload.php'); use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Firefox\FirefoxOptions; use Facebook\WebDriver\Firefox\FirefoxProfile; $profile = new FirefoxProfile(); $profile->setPreference('general.useragent.override', 'Custom-Agent'); // Change user-agent $profile->setPreference('intl.accept_languages', 'es'); // Setting accept language to Spanish $options = new FirefoxOptions(); $options->setProfile($profile); $capabilities = DesiredCapabilities::firefox(); $capabilities->setCapability(FirefoxOptions::CAPABILITY, $options); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('tb:options', [ 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'firefox profile example' ]); $web_driver = RemoteWebDriver::create( "https://hub.testingbot.com/wd/hub", $capabilities ); from selenium import webdriver from selenium.webdriver.firefox.options import Options profile = webdriver.FirefoxProfile() profile.set_preference('general.useragent.override', 'Custom-Agent') # Change user-agent profile.set_preference('intl.accept_languages', 'es') # Setting accept language to Spanish profile.update_preferences() options = Options() options.profile = profile options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'firefox profile example' }) driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) const { Builder } = require('selenium-webdriver'); const firefox = require('selenium-webdriver/firefox'); async function main() { let options = new firefox.Options(); options.setPreference('general.useragent.override', 'Custom-Agent'); // Change user-agent options.setPreference('intl.accept_languages', 'es'); // Setting accept language to Spanish options.setBrowserVersion('latest'); options.setPlatformName('WIN10'); options.set('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'firefox profile example' }); let driver = await new Builder() .usingServer('https://hub.testingbot.com/wd/hub') .setFirefoxOptions(options) .build(); } main(); FirefoxProfile profile = new FirefoxProfile(); profile.SetPreference("general.useragent.override", "Custom-Agent"); // Change user-agent profile.SetPreference("intl.accept_languages", "es"); // Setting accept language to Spanish FirefoxOptions options = new FirefoxOptions(); options.Profile = profile; options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "API_KEY", ["secret"] = "API_SECRET", ["name"] = "firefox profile example" }); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/migrate-existing-tests # Migrate your existing tests Migrating your existing Selenium WebDriver tests to use TestingBot is easy. On this page, we'll show you how to modify your existing tests and run them on the browsers in our cloud. ## Authentication First, you'll need to authenticate to the TestingBot cloud. If you haven't already, please [sign up](https://testingbot.com/users/sign_up) for a free trial and find your TestingBot key and secret in the member area. You'll need to use these credentials in your test scripts to authenticate with our cloud. ## Capabilities Capabilities are used to indicate on which browsers you want to test. You can specify a desired browser name, operating system and browser version. For example, let's say you want to test on the latest Chrome browser on Windows 10: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) options = Selenium::WebDriver::Chrome::Options.new options.browser_version = 'latest' options.platform_name = 'WIN10' options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Test' }) ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); tbOptions.put("name", "My First Test"); options.setCapability("tb:options", tbOptions); $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('tb:options', [ 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Test' ]); from selenium.webdriver.chrome.options import Options options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Test' }) const chrome = require('selenium-webdriver/chrome'); let options = new chrome.Options(); options.setBrowserVersion('latest'); options.setPlatformName('WIN10'); options.set('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Test' }); // for Chrome ChromeOptions options = new ChromeOptions(); // for Firefox // FirefoxOptions options = new FirefoxOptions(); // for Safari // SafariOptions options = new SafariOptions(); options.PlatformName = "WIN10"; options.BrowserVersion = "latest"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "API_KEY", ["secret"] = "API_SECRET", ["name"] = "My First Test" }); ## Running tests with Remote WebDriver If you have been running tests on your local machine until now, then you will need to modify your test scripts to start a WebDriver session via Remote WebDriver. Simply send the [capabilities](https://testingbot.com#capabilities) to our cloud endpoint: https://hub.testingbot.com/wd/hub Below is an example on how to do this: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'selenium-webdriver' options = Selenium::WebDriver::Chrome::Options.new options.browser_version = 'latest' options.platform_name = 'WIN10' options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Test' }) driver = Selenium::WebDriver.for(:remote, url: 'https://hub.testingbot.com/wd/hub', options: options ) driver.navigate.to 'https://www.google.com' # Your test logic here driver.quit import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; public class TestingBotSampleTest { public static void main(String[] args) throws Exception { ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); tbOptions.put("name", "My First Test"); options.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver( new URL("https://hub.testingbot.com/wd/hub"), options ); driver.get("https://www.google.com"); // Your test logic here driver.quit(); } } setCapability('platformName', 'WIN10'); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('tb:options', [ 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Test' ]); $driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities ); $driver->get('https://www.google.com'); // Your test logic here $driver->quit(); from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Test' }) driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) driver.get('https://www.google.com') # Your test logic here driver.quit() const { Builder } = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); async function runTest() { let options = new chrome.Options(); options.setBrowserVersion('latest'); options.setPlatformName('WIN10'); options.set('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Test' }); let driver = await new Builder() .usingServer('https://hub.testingbot.com/wd/hub') .setChromeOptions(options) .build(); await driver.get('https://www.google.com'); // Your test logic here await driver.quit(); } runTest(); using System; using System.Collections.Generic; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; namespace SeleniumTest { class Program { static void Main(string[] args) { ChromeOptions options = new ChromeOptions(); options.PlatformName = "WIN10"; options.BrowserVersion = "latest"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "API_KEY", ["secret"] = "API_SECRET", ["name"] = "My First Test" }); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); driver.Navigate().GoToUrl("https://www.google.com"); // Your test logic here driver.Quit(); } } } ## Migrate from one of the test frameworks We have documentation for all the [popular test frameworks](https://testingbot.com/support/web-automate/selenium). Simply follow the documentation and examples to convert your existing tests. If the test framework you are using is not in our documentation, please [contact us](https://testingbot.com/contact/new) and we'll be happy to help. ## Test your private websites on TestingBot TestingBot offers a feature called [TestingBot Tunnel](https://testingbot.com/support/tunnel) which allows you to run tests against websites hosted on your computer or private network. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/permission-popups # Handling permission pop-ups The website you are testing may ask for specific permissions during testing. For example: - [Permission to access the device location](https://testingbot.com#location) - [Permission to access the camera and/or microphone](https://testingbot.com#camera) - [Permission to show notifications](https://testingbot.com#notifications) - [Permission to access clipboard](https://testingbot.com#clipboard) The browser might show a popup or prompt, asking for user permission. In case of Automated Testing, you'll need a way to automatically approve/deny these requests. Below we'll show you how to do this with your Automated Tests. ## Location Permission A popup will appear when the website or mobile app asks the user for the location. You can choose to **Allow** or **Block** this request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'selenium-webdriver' # 0 - Default, 1 - Allow, 2 - Block caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"prefs" => { "profile.default_content_setting_values.geolocation" => 1 } }) caps['browserName'] = 'Chrome' caps['version'] = 'latest' caps['platform'] = 'WIN10' driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) driver.navigate.to "https://the-internet.herokuapp.com/geolocation" driver.find_element(:xpath, "//*[@id='content']/div/button").click; sleep 5 driver.quit import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class AllowLocationPopup { public static final String URL = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "Chrome"); caps.setCapability("version", "latest"); caps.setCapability("platform", "WIN10"); ChromeOptions options = new ChromeOptions(); Map prefs = new HashMap(); Map profile = new HashMap(); Map contentSettings = new HashMap(); // 0 - Default, 1 - Allow, 2 - Block contentSettings.put("geolocation", 1); profile.put("managed_default_content_settings", contentSettings); prefs.put("profile", profile); options.setExperimentalOption("prefs", prefs); caps.setCapability(ChromeOptions.CAPABILITY, options); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("https://the-internet.herokuapp.com/geolocation"); driver.findElement(By.xpath("//*[@id='content']/div/button")).click(); Thread.sleep(5000); driver.quit(); } } setExperimentalOption('prefs', [ 'profile.default_content_setting_values.geolocation' => 1 ]); $caps = DesiredCapabilities::chrome(); $caps->setCapability( ChromeOptions::CAPABILITY_W3C, // There is a bug in php-webdriver, so ->toArray() is needed! $options->toArray() ); $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000 ); $web_driver->get("https://google.com"); $element = $web_driver->findElement(WebDriverBy::name("q")); if ($element) { $element->sendKeys("TestingBot"); $element->submit(); } print $web_driver->getTitle(); $web_driver->quit(); ?> from time import sleep from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options chrome_options = Options() # 0 - Default, 1 - Allow, 2 - Block chrome_options.add_experimental_option("prefs", { "profile.default_content_setting_values.geolocation": 1}) desired_cap = chrome_options.to_capabilities() desired_cap.update({ 'version': 'latest', 'platform': 'WIN10', 'browserName': 'chrome' }) driver = webdriver.Remote(command_executor='https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) driver.get("https://the-internet.herokuapp.com/geolocation") driver.find_element_by_xpath("//*[@id='content']/div/button").click() sleep(10) driver.quit() const chrome = require("selenium-webdriver/chrome"); const capabilities = { 'browserName' : 'Chrome', 'version' : 'latest', 'platform' : 'WIN10' 'goog:chromeOptions': { prefs: { // 0 - Default, 1 - Allow this permission request, 2 - Block (deny) this permission request 'profile.managed_default_content_settings.geolocation' : 1 } } } const driver = new webdriver.Builder() .usingServer('https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); driver.get('https://the-internet.herokuapp.com/geolocation') .then(function(){ driver.findElement(webdriver.By.xpath("//*[@id='content']/div/button")).click() .then(function(){ driver.quit(); }); }); using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; namespace GeoCSharp { public class Program { public static void Main(string[] args) { RemoteWebDriver driver; Dictionary profile = new Dictionary(); // 0 - Default, 1 - Allow, 2 - Block profile.Add("profile.default_content_setting_values.geolocation", 1); Dictionary chromeOptions = new Dictionary(); chromeOptions.Add("prefs", profile); ChromeOptions capability = new ChromeOptions(); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("key", "key", true); capability.AddAdditionalCapability("secret", "secret", true); capability.AddAdditionalCapability("chromeOptions", chromeOptions, true); driver = new RemoteWebDriver(new Uri("http://hub.testingbot.com/wd/hub/"), capability); driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/geolocation"); driver.FindElement(By.XPath("//*[@id='content']/div/button")).Click(); Thread.Sleep(5000); driver.Quit(); } } } ## Camera and Microphone Permissions During your Automated Testing, you might want to test and handle Camera and Microphone permissions. Please see the example below, it shows you how to either **Allow** or **Block** a request from your webapp. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'selenium-webdriver' # Configure ChromeOptions to pass a fake media stream during testing # You can use this with Edge as well caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"args" => ['--use-fake-device-for-media-stream', '--use-fake-ui-for-media-stream'] }) caps['browserName'] = 'Chrome' caps['version'] = 'latest' caps['platform'] = 'WIN10' driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) # Web Cam Test driver.navigate.to "https://webcamtests.com/check" sleep(5) driver.find_element(:id, "webcam-launcher").click sleep(2) # Microphone Test driver.navigate.to "https://www.vidyard.com/mic-test/" sleep(5) driver.find_element(:xpath, "//a[@id='start-test']").click sleep(2) driver.quit import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; public class AllowCameraPopupChrome { public static final String URL = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { // Configure ChromeOptions to pass a fake media stream ChromeOptions options = new ChromeOptions(); options.addArguments("use-fake-device-for-media-stream"); options.addArguments("use-fake-ui-for-media-stream"); DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "Chrome"); caps.setCapability("version", "latest"); caps.setCapability("platform", "WIN10"); caps.setCapability(ChromeOptions.CAPABILITY, options); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); // WebCam Test driver.get("https://webcamtests.com/check"); Thread.sleep(5000); driver.findElement(By.id("webcam-launcher")).click(); Thread.sleep(2000); // Microphone Test driver.get("https://www.vidyard.com/mic-test/"); Thread.sleep(2000); driver.findElement(By.xpath("(//a[@id='start-test']")).click(); Thread.sleep(2000); driver.quit(); } } addArguments(array("use-fake-device-for-media-stream", "use-fake-ui-for-media-stream")); $caps = DesiredCapabilities::chrome(); $caps->setCapability( ChromeOptions::CAPABILITY, $options ); $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000 ); // WebCam Test $web_driver->get("https://webcamtests.com/check"); $element = $web_driver->findElement(WebDriverBy::id("webcam-launcher")); if ($element) { $element->click(); } // Microphone Test $web_driver->get("https://www.vidyard.com/mic-test"); $element = $web_driver->findElement(WebDriverBy::xpath("(//a[@id='start-test']"))); if ($element) { $element->click(); } $web_driver->quit(); ?> from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options import time desired_cap = { 'version': 'latest', 'platform': 'WIN10', 'browserName': 'chrome' # Configure ChromeOptions to pass fake media stream 'chromeOptions': { 'args': ["--use-fake-device-for-media-stream", "--use-fake-ui-for-media-stream"] } } driver = webdriver.Remote(command_executor='https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) # WebCam Test driver.get("https://webcamtests.com/check") time.sleep(5) driver.find_element_by_id("webcam-launcher").click() time.sleep(2) # Mic Test driver.get("https://www.vidyard.com/mic-test/") time.sleep(5) driver.find_element_by_xpath("//a[@id='start-test']").click() time.sleep(2) driver.quit() const webdriver = require('selenium-webdriver'); const chrome = require("selenium-webdriver/chrome"); const capabilities = { 'browserName' : 'Chrome', 'version' : 'latest', 'platform' : 'WIN10', // Configure ChromeOptions to pass fake media stream 'goog:chromeOptions': { 'args': ["--use-fake-device-for-media-stream", "--use-fake-ui-for-media-stream"] } } const driver = new webdriver.Builder() .usingServer('https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); // Webcam Test driver.get('https://webcamtests.com/check') .then(function() { setTimeout(function() { driver.findElement(webdriver.By.id("webcam-launcher")).click() .then(function() { setTimeout(function() { // Microphone Test driver.get('https://www.vidyard.com/mic-test/') .then(function() { driver.findElement(webdriver.By.xpath("//a[@id='start-test']")).click() .then(function() { setTimeout(function() { driver.quit(); }, 2000); }); }); }, 2000); }); }, 2000); }); using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using System.Threading; using OpenQA.Selenium.Chrome; namespace SampleCSharp { public class AllowCameraMicPopupChrome { static void Main(string[] args) { IWebDriver driver; //Configure ChromeOptions to pass fake media stream ChromeOptions chromeOptions = new ChromeOptions(); chromeOptions.AddArgument("--use-fake-device-for-media-stream"); chromeOptions.AddArgument("--use-fake-ui-for-media-stream"); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("key", "key", true); capability.AddAdditionalCapability("secret", "secret", true); capability.AddAdditionalCapability("chromeOptions", chromeOptions, true); driver = new RemoteWebDriver(new Uri("http://hub.testingbot.com/wd/hub/"), capability); // Webcam Test driver.Navigate().GoToUrl("https://webcamtests.com/check"); Thread.Sleep(2000); driver.FindElement(By.Id("webcam-launcher")).Click(); Thread.Sleep(5000); // Microphone Test driver.Navigate().GoToUrl("https://www.vidyard.com/mic-test/"); Thread.Sleep(2000); driver.FindElement(By.XPath("//a[@id='start-test']")).Click(); Thread.Sleep(2000); driver.Quit(); } } } ## Notification Permissions During your Automated Testing, the website might request access to show notifications. Please see the example below, it shows you how to either **Allow** or **Block** a notification request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[Node](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'selenium-webdriver' # 0 - Default, 1 - Allow, 2 - Block caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"prefs" => { "profile.default_content_setting_values.notifications" => 1 } }) caps['browserName'] = 'Chrome' caps['version'] = 'latest' caps['platform'] = 'WIN10' driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) driver.navigate.to "https://web-push-book.gauntface.com/demos/notification-examples/" driver.find_element(:xpath, "//body/main[1]/p[3]/input[1]").click; sleep(2) driver.quit import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class AllowNotificationPopupDesktop { public static final String URL = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "Chrome"); caps.setCapability("version", "latest"); caps.setCapability("platform", "WIN10"); caps.setCapability(ChromeOptions.CAPABILITY, options); ChromeOptions options = new ChromeOptions(); Map prefs = new HashMap(); Map profile = new HashMap(); Map contentSettings = new HashMap(); // 0 - Default, 1 - Allow, 2 - Block contentSettings.put("notifications", 1); profile.put("managed_default_content_settings", contentSettings); prefs.put("profile", profile); options.setExperimentalOption("prefs", prefs); caps.setCapability(ChromeOptions.CAPABILITY, options); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("https://web-push-book.gauntface.com/demos/notification-examples/"); driver.findElement(By.xpath("//body/main[1]/p[3]/input[1]")).click(); Thread.sleep(2000); driver.quit(); } } setExperimentalOption('prefs', [ 'profile.default_content_setting_values.notifications' => 1 ]); $caps = DesiredCapabilities::chrome(); $caps->setCapability( ChromeOptions::CAPABILITY_W3C, // There is a bug in php-webdriver, so ->toArray() is needed! $options->toArray() ); $web_driver = RemoteWebDriver::create( "https://api_key:api_secret@hub.testingbot.com/wd/hub", $caps, 120000 ); $web_driver->get("https://web-push-book.gauntface.com/demos/notification-examples/"); $element = $web_driver->findElement(WebDriverBy::xpath("//body/main[1]/p[3]/input[1]")); if ($element) { $element->click(); } $web_driver->quit(); ?> from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options import time # 0 - Default, 1 - Allow, 2 - Block chrome_options = Options() chrome_options.add_experimental_option("prefs", { "profile.default_content_setting_values.notifications": 1}) desired_cap = chrome_options.to_capabilities() desired_cap.update({ 'version': 'latest', 'platform': 'WIN10', 'browserName': 'chrome' }) driver = webdriver.Remote(command_executor='https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) driver.get("https://web-push-book.gauntface.com/demos/notification-examples/") driver.find_element_by_xpath("//body/main[1]/p[3]/input[1]").click() time.sleep(2) driver.quit() const webdriver = require('selenium-webdriver'); const chrome = require("selenium-webdriver/chrome"); const capabilities = { 'browserName' : 'Chrome', 'version' : 'latest', 'platform' : 'WIN10', 'goog:chromeOptions': { prefs: { // 0 - Default, 1 - Allow, 2 - Block 'profile.managed_default_content_settings.notifications': 1 } } } const driver = new webdriver.Builder() .usingServer('https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); driver.get('https://web-push-book.gauntface.com/demos/notification-examples/') .then(function() { driver.findElement(webdriver.By.xpath("//body/main[1]/p[3]/input[1]")).click() .then(function() { driver.quit(); }); }); using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using System.Threading; using System.Collections.Generic; using OpenQA.Selenium.Chrome; namespace SampleCSharp { public class Program { static void Main(string[] args) { RemoteWebDriver driver; Dictionary profile = new Dictionary(); // 0 - Default, 1 - Allow, 2 - Block profile.Add("profile.default_content_setting_values.notifications", 1); Dictionary chromeOptions = new Dictionary(); chromeOptions.Add("prefs", profile); // SET CAPABILITY ChromeOptions capability = new ChromeOptions(); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("key", "key", true); capability.AddAdditionalCapability("secret", "secret", true); capability.AddAdditionalCapability("chromeOptions", chromeOptions, true); driver = new RemoteWebDriver(new Uri("http://hub.testingbot.com/wd/hub/"), capability); driver.Navigate().GoToUrl("https://web-push-book.gauntface.com/demos/notification-examples/"); driver.FindElement(By.XPath("//body/main[1]/p[3]/input[1]")).Click(); Thread.Sleep(2000); driver.Quit(); } } } ## Clipboard Permissions During your Automated Testing, Javascript code on the website you are testing might ask for clipboard permission. This permission dialog asks the user if the website can read (and/or write) to the clipboard. ![Clipboard Access Request example](https://testingbot.com/assets/support/clipboard-permission-d786d434b15e680ce09b16d2655082be94f712a638ccba2394051f7cdc6cc962.webp) Usually, this is accomplished by running a piece of Javascript code, similar to this snippet: const text = await navigator.clipboard.readText(); Please see the example below, it shows you how to either **Allow** or **Block** a clipboard access request. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[Node](https://testingbot.com#)[C#](https://testingbot.com#) require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.chrome("chromeOptions" => {"prefs" => { "profile.content_settings.exceptions.clipboard" => '*': {'setting': 1} } }) caps['browserName'] = 'Chrome' caps['version'] = 'latest' caps['platform'] = 'WIN10' driver = Selenium::WebDriver.for(:remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps) driver.navigate.to "https://permission.site/#read-text" driver.find_element(:id, "read-text").click; sleep(2) driver.quit import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.net.URL; import java.util.HashMap; import java.util.Map; public class AllowClipboardPermission { public static final String URL = "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub"; private static Map getClipBoardSettingsMap(int settingValue) throws JsonProcessingException { Map map = new HashMap<>(); map.put("last_modified",String.valueOf(System.currentTimeMillis())); map.put("setting", settingValue); Map cbPreference = new HashMap<>(); cbPreference.put("[*.],*",map); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(cbPreference); logger.info("clipboardSettingJson: " + json); return cbPreference; } public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "Chrome"); caps.setCapability("version", "latest"); caps.setCapability("platform", "WIN10"); caps.setCapability(ChromeOptions.CAPABILITY, options); ChromeOptions options = new ChromeOptions(); Map prefs = new HashMap(); Map profile = new HashMap(); Map contentSettings = new HashMap(); prefs.put("profile.content_settings.exceptions.clipboard", getClipBoardSettingsMap(1)); options.setExperimentalOption("prefs", prefs); caps.setCapability(ChromeOptions.CAPABILITY, options); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("https://permission.site/#read-text"); driver.findElement(By.id("read-text")).click(); Thread.sleep(2000); driver.quit(); } } // no example yet from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.chrome.options import Options import time chrome_options = Options() chrome_options.add_preference('profile.content_settings.exceptions.clipboard', { '*': {'setting': 1} }) desired_cap = chrome_options.to_capabilities() desired_cap.update({ 'version': 'latest', 'platform': 'WIN10', 'browserName': 'chrome' }) driver = webdriver.Remote(command_executor='https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub', desired_capabilities=desired_cap) driver.get("https://permission.site/#read-text") driver.find_element_by_id("read-text").click() time.sleep(2) driver.quit() const webdriver = require('selenium-webdriver'); const { Options } = require('selenium-webdriver/chrome'); const options = new Options() options.setUserPreferences({ profile: { content_settings: { exceptions: { clipboard: { ['https://permission.site,*']: { "expiration": "0", "last_modified": Date.now(), "model": 0, "setting": 1 }, } } } } }) const capabilities = { 'browserName' : 'Chrome', 'version' : 'latest', 'platform' : 'WIN10' } capabilities.merge(options.toCapabilities()); const driver = new webdriver.Builder() .usingServer('https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); driver.get('https://permission.site/#read-text') .then(function() { driver.findElement(webdriver.By.id("read-text")).click() .then(function() { driver.quit(); }); }); using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using System.Threading; using System.Collections.Generic; using OpenQA.Selenium.Chrome; namespace SampleCSharp { public class Program { static void Main(string[] args) { RemoteWebDriver driver; ChromeOptions capability = new ChromeOptions(); var clipboardException = new Dictionary { {"[*.]myurl.com,*", new Dictionary { {"last_modified", DateTimeOffset.Now.ToUnixTimeMilliseconds()}, {"setting", 1} } } }; profile.Add("profile.content_settings.exceptions.clipboard", clipboardException); chromeOptions.Add("prefs", profile); capability.AddAdditionalCapability("browserName", "Chrome", true); capability.AddAdditionalCapability("version", "latest", true); capability.AddAdditionalCapability("platform", "WIN10", true); capability.AddAdditionalCapability("key", "key", true); capability.AddAdditionalCapability("secret", "secret", true); capability.AddAdditionalCapability("chromeOptions", chromeOptions, true); driver = new RemoteWebDriver(new Uri("https://hub.testingbot.com/wd/hub/"), capability); driver.Navigate().GoToUrl("https://permission.site/#read-text"); driver.FindElement(By.Id("read-text")).Click(); Thread.Sleep(2000); driver.Quit(); } } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/test-file-downloads # Test File Downloads TestingBot provides custom Selenium WebDriver commands to verify if a file was downloaded during a test automation session. Below you'll find examples on how to: - [Download files on remote desktop instances during your test](https://testingbot.com#download) - [Verify that the file was downloaded successfully](https://testingbot.com#verify) - [Retrieve (meta) properties from the downloaded file](https://testingbot.com#retrieve) - [Retrieve the contents of the downloaded file](https://testingbot.com#contents) All functions below can be used with a `fileName` argument, or without an argument. If you do not specify a specific filename, TestingBot will automatically select the most recent downloaded file. ## Download files on remote desktop instances during your test As part of your test automation flow, you might want to test download functionality of your webapp. In the example below, we'll first show you how to instruct the remote TestingBot browser to download a file on the TestingBot virtual machine. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' options = Selenium::WebDriver::Chrome::Options.new options.browser_version = 'latest' options.platform_name = 'WIN10' options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Download Test' }) driver = Selenium::WebDriver.for( :remote, :url => "https://hub.testingbot.com/wd/hub", :options => options ) driver.navigate.to "https://testingbot.com/security" # click the download button element = driver.find_element(:css, "body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a") element.click sleep 6 driver.quit ChromeOptions options = new ChromeOptions(); options.setPlatformName("WIN10"); options.setBrowserVersion("latest"); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); tbOptions.put("name", "My First Download Test"); options.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver(new URL("https://hub.testingbot.com/wd/hub"), options); driver.get("https://testingbot.com/security"); driver.findElement(By.cssSelector("body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a")).click(); Thread.sleep(1000); driver.quit(); require_once('vendor/autoload.php'); use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\WebDriverBy; $options = new ChromeOptions(); $capabilities = DesiredCapabilities::chrome(); $capabilities->setCapability(ChromeOptions::CAPABILITY, $options); $capabilities->setCapability('browserVersion', 'latest'); $capabilities->setCapability('platformName', 'WIN10'); $capabilities->setCapability('tb:options', [ 'key' => 'API_KEY', 'secret' => 'API_SECRET', 'name' => 'My First Download Test' ]); $web_driver = RemoteWebDriver::create( "https://hub.testingbot.com/wd/hub", $capabilities ); $web_driver->get("https://testingbot.com/security"); $web_driver->findElement(WebDriverBy::cssSelector("body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a"))->click(); $web_driver->quit(); import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options options = Options() options.browser_version = 'latest' options.platform_name = 'WIN10' options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Download Test' }) driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) driver.get("https://testingbot.com/security") driver.find_element(By.CSS_SELECTOR, "body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a").click() time.sleep(2) driver.quit() const { Builder, By } = require('selenium-webdriver'); const chrome = require('selenium-webdriver/chrome'); const fs = require('fs'); async function main() { let options = new chrome.Options(); options.setBrowserVersion('latest'); options.setPlatformName('WIN10'); options.set('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET', 'name': 'My First Download Test' }); let driver = await new Builder() .usingServer('https://hub.testingbot.com/wd/hub') .setChromeOptions(options) .build(); await driver.get('https://testingbot.com/security'); await driver.findElement(By.css("body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a")).click(); await driver.sleep(2000); await driver.quit(); } main(); using System; using System.Collections.Generic; using OpenQA.Selenium; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using System.IO; using System.Threading; namespace SeleniumTest { class FileDownload { static void Main(string[] args) { ChromeOptions options = new ChromeOptions(); options.BrowserVersion = "latest"; options.PlatformName = "WIN10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "API_KEY", ["secret"] = "API_SECRET", ["name"] = "My First Download Test" }); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); driver.Navigate().GoToUrl("https://testingbot.com/security"); driver.FindElement(By.CssSelector("body > div.bigHeader.enterprise > div.hero.enterprise.feature > div > div > div > a")).Click(); Thread.Sleep(2000); driver.Quit(); } } } ## Verify that the file was downloaded successfully Once you've downloaded a file during your test automation, you might want to check if it was downloaded correctly (does it exist on the disk?). To perform this check, TestingBot has created a custom `tb:fileExists` command which can be used with the JavascriptExecutor provided by Selenium WebDriver. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script("tb:fileExists", { "fileName": "...the file name...", }) Map fileMap = new HashMap<>(); fileMap.put("fileName", "...the file name..."); ((JavascriptExecutor) driver).executeScript("tb:fileExists", fileMap); $driver->executeScript("tb:fileExists", [ "fileName" => "...the file name..." ]); driver.execute_script("tb:fileExists", { "fileName": "...the file name..." }) await driver.executeScript('tb:fileExists', { "fileName": "...the file name..." }) ((IJavaScriptExecutor)driver).ExecuteScript("tb:fileExists", "{\"fileName\":\"...the file name...\"}"); ## Retrieve (meta) properties from the downloaded file You can check the integrity of the downloaded file during your test, with the `tb:fileProperties` command. This will return the following file (meta) data: { "changed_time": 1649947630, "created_time": 1649947629, "modified_time": 1649947630, "size": 114123, "md5": "5d4f7a7d4335c99048c3cc7563ffa7bf" } - `changed_time`: Indicates, in unix epoch time, when the file (permission or content) was changed. - `created_time`: Indicates, in unix epoch time, when the file was downloaded. - `modified_time`: Indicates, in unix epoch time, when the file content was changed. - `size`: The size of the downloaded file, in bytes. - `md5`: The MD5 checksum of the downloaded file. Useful to verify the integrity of the file. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script("tb:fileProperties", { "fileName": "...the file name...", }) Map fileMap = new HashMap<>(); fileMap.put("fileName", "...the file name..."); ((JavascriptExecutor) driver).executeScript("tb:fileProperties", fileMap); $driver->executeScript("tb:fileProperties", [ "fileName" => "...the file name..." ]); driver.execute_script("tb:fileProperties", { "fileName": "...the file name..." }) await driver.executeScript('tb:fileProperties', { "fileName": "...the file name..." }) ((IJavaScriptExecutor)driver).ExecuteScript("tb:fileProperties", "{\"fileName\":\"...the file name...\"}"); ## Retrieve the contents of the downloaded file It is possible to download the file, which was downloaded on the remote TestingBot machine, to your own computer. TestingBot has created a custom command, `tb:fileContent`, which will return a Base64-encoded string of the file content. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) get_file_content = driver.execute_script("tb:fileContent", { "fileName": "...the file name...", }) decoded_content = Base64.decode64(get_file_content); f = File.open("filename.txt", "wb") f.write(decoded_content) f.close Map fileMap = new HashMap<>(); fileMap.put("fileName", "...the file name..."); String base64EncodedFile = (String) ((JavascriptExecutor) driver).executeScript("tb:fileContent", fileMap); byte[] data = Base64.getDecoder().decode(base64EncodedFile); OutputStream stream = new FileOutputStream("filename.txt"); stream.write(data); stream.close(); $driver->executeScript("tb:fileContent", [ "fileName" => "...the file name..." ]); get_file_content = driver.execute_script("tb:fileContent", { "fileName": "...the file name..." }) data = base64.b64decode(get_file_content) f = open("filename.txt", "wb") f.write(data) let base64data = await driver.executeScript('tb:fileContent', { "fileName": "...the file name..." }) let data = Buffer.from(base64data, 'base64'); fs.writeFileSync('filename.txt', data); console.log('File ready'); string base64encode = (string) ((IJavaScriptExecutor)driver).ExecuteScript("tb:fileContent", "{\"fileName\":\"...the file name...\"}"); byte[] b = Convert.FromBase64String(base64encode); File.WriteAllBytes(@"filename.txt", b); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/auto-it # AutoIT AutoIT is a scripting language, with syntax similar to BASIC, used to automate programs on Windows. TestingBot has created a custom command, `tb:autoit`, which you can use during your Selenium WebDriver tests to automate parts of Windows and Windows GUI programs. AutoIT is compatible with all versions of Windows and provides many automation features, including: - Manipulate windows and processes - Interact with standard Windows components - Simulate keystrokes and mouse movements In the example below, we will show you a basic example of what an autoIT script looks like. MsgBox(0, "My Title", "Hello from AutoIT") ## Running AutoIT during a Selenium WebDriver test TestingBot has created a custom command, `tb:autoit`. You can use this command to send AutoIT scripts during your WebDriver test. You could for example use AutoIT scripts to automate a native dialog, for example a file upload dialog, opened by the browser during your WebDriver test. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) payload = <<-EOF MsgBox(0, "My Title", "Hello from AutoIT") EOF driver.execute_script("tb:autoit", payload) String autoItContent = "MsgBox(0, \"My Title\", \"Hello from AutoIT\")"; ((JavascriptExecutor) driver).executeScript("tb:autoit", autoItContent); $autoItScript = 'MsgBox(0, "My Title", "Hello from AutoIT")'; $driver->executeScript("tb:autoit", $autoItScript); autoItContent = "MsgBox(0, \"My Title\", \"Hello from AutoIT\")" driver.execute_script("tb:autoit", autoItContent) browser.execute('tb:autoit', 'MsgBox(0, "My Title", "Hello from AutoIT")') ((IJavaScriptExecutor)driver).ExecuteScript("tb:autoit", "MsgBox(0, \"My Title\", \"Hello from AutoIT\")"); ### Specifying an URL to AutoIt script Instead of specifying the AutoIT commands in the `tb:autoit` command, you can also specify a URL to a file that contains all the AutoIT commands: [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) driver.execute_script("tb:autoit", "https://testingbot.com/autoit/example.au3") ((JavascriptExecutor) driver).executeScript("tb:autoit", "https://testingbot.com/autoit/example.au3"); $driver->executeScript("tb:autoit", "https://testingbot.com/autoit/example.au3"); driver.execute_script("tb:autoit", "https://testingbot.com/autoit/example.au3") browser.execute('tb:autoit', "'ttps://testingbot.com/autoit/example.au3') ((IJavaScriptExecutor)driver).ExecuteScript("tb:autoit", "https://testingbot.com/autoit/example.au3"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/osascript # Applescript Applescript (or osascript) is a scripting language which comes by default on macOS. It allows for automating various (native) macOS applications and can be used in combination with Selenium WebDriver via TestingBot's custom `tb:osascript` command. In the example below, you'll find a simple Applescript example which will open Safari and enable automation. tell application "Safari" launch activate tell application "System Events" set v to (value of attribute "AXMenuItemMarkChar" of menu item "Allow Remote Automation" of menu "Develop" of menu bar item "Develop" of menu bar 1 of application process "Safari") if v is missing value then click menu item "Allow Remote Automation" of menu "Develop" of menu bar item "Develop" of menu bar 1 of application process "Safari" else log "OK" end if end tell quit end tell ## Running Applescript during a Selenium WebDriver test TestingBot has created a custom command, `tb:osascript`, which you can use to pass in your specific Applescript at any point during your (macOS) WebDriver test. For example, you can use Applescript to automate a native dialog appearing during your test, such as a file upload dialog from the browser. You can specify multiple different Applescripts at any point during your test. The session will wait until the script has ended, before proceeding to the other WebDriver commands. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) applescript_content = <<-EOF display alert "Success!" EOF driver.execute_script("tb:osascript", { script: applescript_content }) String appleScriptContent = "display alert \"Success!\""; Map osaMap = new HashMap<>(); osaMaposaMap.put("script", appleScriptContent); ((JavascriptExecutor) driver).executeScript("tb:osascript", osaMap); $osaScript = 'display alert "Success!"'; $driver->executeScript("tb:osascript", ["script" => $osaScript]); osaScriptContent = "display alert \"Success!\"" driver.execute_script("tb:osascript", { "script": osaScriptContent }) browser.execute('tb:osascript', { "script": 'display alert "Success!"' }) ((IJavaScriptExecutor)driver).ExecuteScript("tb:osascript", "{\"script\":\"display alert \"Success!\"\"}}"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/ie-mode-on-edge # IE mode on Edge browser Some (older) websites are built to run on Internet Explorer and might have features that are not supported by current browsers, such as Microsoft Edge. Microsoft Edge is the successor of Internet Explorer. Microsoft Edge provides an **Internet Explorer Mode** with Microsoft Edge, which allows you to run the Edge browser just like you would be running an IE 11 browser. IE mode on Microsoft Edge is supported from Selenium version 4 and higher. ## Start using Internet Explorer Mode To run your Selenium 4 tests with IE Mode and Edge, you can use the `ie.edgechromium` capability with `se:ieOptions`. Please see the example below. [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) options = Selenium::WebDriver::IE::Options.new options.attach_to_edge_chrome = true options.add_option('tb:options', { 'key' => 'API_KEY', 'secret' => 'API_SECRET' }) driver = Selenium::WebDriver.for(:remote, url: 'https://hub.testingbot.com/wd/hub', options: options ) InternetExplorerOptions options = new InternetExplorerOptions(); options.attachToEdgeChrome(); HashMap tbOptions = new HashMap<>(); tbOptions.put("key", "API_KEY"); tbOptions.put("secret", "API_SECRET"); options.setCapability("tb:options", tbOptions); WebDriver driver = new RemoteWebDriver(new URL("https://hub.testingbot.com/wd/hub"), options); $capabilities = DesiredCapabilities::internetExplorer(); $capabilities->setCapability('platformName', 'Windows 10'); $capabilities->setCapability('se:ieOptions', [ 'ie.edgechromium' => true ]); $capabilities->setCapability('tb:options', [ 'key' => 'API_KEY', 'secret' => 'API_SECRET' ]); $driver = RemoteWebDriver::create( 'https://hub.testingbot.com/wd/hub', $capabilities ); from selenium.webdriver.ie.options import Options options = Options() options.attach_to_edge_chrome = True options.set_capability('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET' }) driver = webdriver.Remote( command_executor='https://hub.testingbot.com/wd/hub', options=options ) const { Builder } = require('selenium-webdriver'); const ie = require('selenium-webdriver/ie'); let options = new ie.Options(); options.setEdgeChromium(true); options.set('tb:options', { 'key': 'API_KEY', 'secret': 'API_SECRET' }); let driver = await new Builder() .usingServer('https://hub.testingbot.com/wd/hub') .setIeOptions(options) .build(); var options = new InternetExplorerOptions(); options.AttachToEdgeChrome = true; options.PlatformName = "Windows 10"; options.AddAdditionalOption("tb:options", new Dictionary { ["key"] = "API_KEY", ["secret"] = "API_SECRET" }); IWebDriver driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub"), options ); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/selenium/grid # Selenium Grid and TestingBot Selenium Grid is an open-source project that provides distributed testing on a variety of browsers, across different machines called nodes. Setting up and maintaining a Selenium Grid takes time and effort. For every new browser version release, the configuration will need to be adjusted. You'll need to configure the appropriate driver (ChromeDriver, GeckoDriver, SafariDriver, EdgeDriver, ...), provision enough hardware and tune for performance. Running tests on TestingBot takes away the hassle of setting up and configuring a Selenium Grid yourself. TestingBot supports 100% compatibility with Selenium and Selenium Grid and has enhanced it with new useful features: - Screen recording and automated screenshots for every session. - Every test runs on a single-use VM, configured for performance and stability. - Integration with various [CI/CD solutions](https://testingbot.com/support/integrations/ci-cd). - Share test results and capacity with [other team members](https://testingbot.com/support/team/sub-accounts). - Insight into test failures with [Test Insights](https://testingbot.com/support/analytics/insights). ## Installing Selenium Grid To get started, please make sure you have a machine that has these things available: - Java JRE 11 - Download the [Selenium Server JAR file](https://github.com/SeleniumHQ/selenium/releases/latest) The machine will serve as a Selenium Grid endpoint. Tests will need to use this machine's IP address to forward test requests to. The Grid will then forward the requests to the appropriate nodes connected to the grid. To install the Grid, please follow the [Selenium Grid documentation](https://www.selenium.dev/documentation/grid/getting_started/). ## Running tests on Selenium Grid Once you have installed and configured your Selenium grid, you are ready to configure your tests to use the Selenium Grid. Below we'll show an example on how to change your existing tests from running on a local browser on your computer, to using the Selenium Grid you've just set up. [Local Execution](https://testingbot.com#)[Remote Execution](https://testingbot.com#) WebDriver driver = new ChromeDriver(); driver.get("https://www.google.com/ncr"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); driver.quit(); WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444"), new ChromeOptions()); driver.get("https://www.google.com/ncr"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); driver.quit(); In the example above we assume the Selenium Grid was set up on the same machine as the test you are running it from (`http://localhost:4444`). ## Extending Selenium Grid with TestingBot Once you have your own Selenium Grid running, you might want to extend it with browsers that are currently not available on your local network. Adding macOS, mobile browsers and physical devices takes a lot of effort. Expand your Selenium Grid with TestingBot's extensive grid of browsers and devices. Selenium Grid offers a **Relay** feature that enables a local Selenium Grid to add TestingBot as an extra node. This means your tests can target browsers and devices that are not available on your local Selenium Grid, while still using the nodes that are available from your local Grid. This results in a hybrid solution of using a local Grid, with low latency, and the TestingBot Grid with extensive coverage. ### Create a toml Configuration File Below is a sample `config.toml` configuration file: [node] detect-drivers = false [relay] url = "https://hub.testingbot.com/wd/hub" configs = [ "5", '{"browserName": "chrome", "platformName": "Windows 11", "browserVersion": "latest"}', "10", '{"browserName": "firefox", "platformName": "Windows 11", "browserVersion": "latest"}', "5", '{"browserName": "safari", "platformName": "macOS 15", "browserVersion": "18"}', "2", '{"browserName": "safari", "platformName": "iOS", "appium:platformVersion": "18.0", "appium:deviceName": "iPhone 16"}', "2", '{"browserName": "chrome", "platformName": "android", "appium:platformVersion": "15.0", "appium:deviceName": "Pixel 9"}' ] This will add 5 extra browser combinations, through the use of the Selenium Grid `relay` function. The configuration determines the capabilities that will be relayed to TestingBot, together with the maximum number of concurrent tests per configuration. We can now start your local Selenium grid with the extra relay functionality: java -jar selenium-server-.jar node --config config.toml Now your tests can use your own Selenium grid to run tests on your own nodes, as well as on TestingBot. ### Run a test on a Selenium Grid The following example shows how to run a test on your local Selenium Grid with forwarding to TestingBot. SafariOptions browserOptions = new SafariOptions(); browserOptions.setPlatformName("macOS 15"); browserOptions.setBrowserVersion("18"); Map tbOptions = new HashMap<>(); tbOptions.put("key", System.getenv("TB_KEY")); tbOptions.put("secret", System.getenv("TB_SECRET")); browserOptions.setCapability("tb:options", tbOptions); RemoteWebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444"), browserOptions); driver.get("https://www.google.com/ncr"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("TestingBot"); element.submit(); driver.quit(); Even though this example references your local Selenium grid, it will forward the test request to TestingBot if the capability is not available on your local grid. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer # Puppeteer Testing [Puppeteer](https://pptr.dev/) is an automation framework which uses the Chrome Devtools protocol to automate a browser. With Puppeteer, you can control a headless (or headful) browser through the Devtools protocol. Compared to Selenium, this might be faster when running automated tests. Please see the documentation below on how to run Puppeteer tests on Chrome, Microsoft Edge and Firefox browsers in the TestingBot cloud. See our [Example Puppeteer Repository](https://github.com/testingbot/puppeteer-testingbot-example) for some examples on how to run Puppeteer tests on TestingBot. ## Installing Puppeteer To install Puppeteer, simply use `yarn` or `npm`: npm i --save puppeteer By default, installing Puppeteer will also install a Chromium build. If you only want to use the TestingBot cloud, you might consider installing Puppeteer without the bundled Chromium build, called `puppeteer-core`: npm i puppeteer-core ## Running your first Puppeteer test To run your first test, please use this example: [Chrome](https://testingbot.com#)[Edge](https://testingbot.com#)[Firefox](https://testingbot.com#) const puppeteer = require('puppeteer-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() This example will start a Chrome Browser, navigate to TestingBot.com and save a PNG screenshot of the homepage. const puppeteer = require('puppeteer-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'edge', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() This example will start a Microsoft Edge Browser, navigate to TestingBot.com and save a PNG screenshot of the homepage. const puppeteer = require('puppeteer-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'firefox', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() This example will start a Firefox Browser, navigate to TestingBot.com and save a PNG screenshot of the homepage. ## Updating your existing Puppeteer scripts With a Puppeteer test, you'll usually start a browser with `await puppeteer.launch()` To start using our service, simply replace this line with our browser endpoint: ### Before const browser = await puppeteer.launch() ### After const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) ## Specifying browser and version To specify on which browser and version your Puppeteer test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Updating Test Details Every Puppeteer test will appear in the TestingBot dashboard, by default as an unnamed test. You can specify various parameters in the `browserWSEndpoint` to customize this. Specify a [name](https://testingbot.com/support/web-automate/puppeteer/options#name), [extra (metadata) information](https://testingbot.com/support/web-automate/puppeteer/options#customdata) or group tests together as a [build](https://testingbot.com/support/web-automate/puppeteer/options#build). TestingBot has created a custom Puppeteer command, which you can use in your tests, to mark a test as passed or failed in the TestingBot dashboard. See the example below, where we run a Puppeteer script and depending on whether the test passes or fails, we send back the correct test status to TestingBot. const puppeteer = require('puppeteer-core') const expect = require('chai').expect (async () => { const browser = await puppeteer.connect({ browserWSEndpoint: 'wss://cloud.testingbot.com?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&platform=WIN10' }) const page = await browser.newPage() await page.goto('https://testingbot.com/') const title = await page.title() try { expect(title).to.equal("Cross Browser Testing and Mobile App Testing. Test on web browsers, mobile emulators, simulators and physical mobile devices.", 'Expected page title is incorrect!') // This is ok, so mark the test as passed await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: true, reason: 'Title matched'}})}`) } catch { // Test failed, mark the test as failed on TestingBot await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: false, reason: 'Title did not match'}})}`) } await browser.close() })() ## Puppeteer and TestingBot Tunnel Using Puppeteer in combination with [TestingBot Tunnel](https://testingbot.com/support/tunnel) allows you to test websites behind a firewall or on your local machine with Puppeteer on TestingBot. ### Setup Tunnel To use TestingBot Tunnel in combination with Puppeteer, you first need to start the TestingBot Tunnel and pass it a `tunnelIdentifier` name of your liking. java -jar testingbot-tunnel.jar key secret -i myPuppeteerTunnel In this example, we'll start a TestingBot Tunnel with identifier **myPuppeteerTunnel**. Next, we'll need to configure our Puppeteer script to use the tunnel, using the same identifier. ### Setup Puppeteer To let Puppeteer know which tunnel we want to use, we need to specify the identifier from before as a parameter. Please see the example below where we pass the `tunnelIdentifier` with **myPuppeteerTunnel**. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', tunnelIdentifier: 'myPuppeteerTunnel' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}`, headless: false }) const page = await browser.newPage() await page.goto('http://localhost:3000') await page.screenshot({ path: 'screenshot.png' }) await browser.close() This Puppeteer script will open the latest Chrome browser on the TestingBot browser grid, use the tunnel to access your localhost website and take a screenshot from that page. ### Puppeteer and TestingBot Tunnel Launcher [testingbot-tunnel-launcher](https://github.com/testingbot/testingbot-tunnel-launcher) is a NodeJS library which allows you to manage the tunnel from within your NodeJS script. To use it, you can install with `npm install testingbot-tunnel-launcher` and use it with Puppeteer: const testingbotTunnel = require('testingbot-tunnel-launcher') const puppeteer = require('puppeteer-core') (async () => { const tunnel = await new Promise((resolve, reject) => { testingbotTunnel({ apiKey: 'api_key', apiSecret: 'api_secret', verbose: true, tunnelIdentifier: 'puppeteerTunnel' }, function (err, tunnel) { if (err) { reject(err) return } resolve(tunnel) }) }) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', tunnelIdentifier: 'puppeteerTunnel' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('http://localhost:8080') await page.screenshot({ path: 'screenshot.png' }) await browser.close() await new Promise((resolve, reject) => { tunnel.close((err) => { if (err) { reject(err) return } resolve() }) }) })() This example will start a new Tunnel, start a Puppeteer script on the latest Chrome version in TestingBot, and take a screenshot of the website running on your local computer `(http://localhost:8080)` ## Debugging Tips Below are some tips on how to debug your Puppeteer scripts. ### Verbose Logging To see logs of what Puppeteer is sending and receiving, you can use this environment variable: `env DEBUG="puppeteer:*"` DEBUG="puppeteer:*" node puppeteer.js ### Slow Motion option With the `slowMo` option you can slow down each operation during the Puppeteer session. To see the result, please specify these options: const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}`, headless: false, slowMo: 250 // slow down by 250ms }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() ## Puppeteer Framework examples - [CodeceptJS](https://testingbot.com/support/web-automate/puppeteer/codeceptjs) `CodeceptJS` is an end-to-end test framework capable of running Puppeteer tests. - [Jest](https://testingbot.com/support/web-automate/puppeteer/jest) `Jest-Puppeteer` allows you to run tests with Jest on browsers controlled with Puppeteer. - [Chromedp](https://testingbot.com/support/web-automate/puppeteer/chromedp) `chromedp` is a Golang framework to use with Puppeteer. - [PyTest](https://testingbot.com/support/web-automate/puppeteer/pytest) `pytest-pyppeteer` is a Python framework to use with Puppeteer. - [WebdriverIO](https://testingbot.com/support/web-automate/puppeteer/webdriverio) `WebdriverIO` is an Automation Test Framework for Node.js. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/capabilities # Puppeteer Capabilities Generator Generate Puppeteer connection options for your automated tests. Choose your browser, device emulation and configuration options to get the exact code you need for your Puppeteer tests. [![Selenium capabilities](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)Selenium](https://testingbot.com/support/web-automate/selenium/capabilities)[![Appium capabilities](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium/capabilities)[![Puppeteer capabilities](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer/capabilities)[![Playwright capabilities](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)Playwright](https://testingbot.com/support/web-automate/playwright/capabilities) Browser Environment ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Resolution800x6001024x7681280x8001280x9601280x10241440x9001680x10501600x12001920x12001920x10802560x1440 ## Project Capabilities Test NameAllows you to customize the name of the test, as it will appear in the dashboard. Build NameGroup tests under the same build identifier for easy retrieval. ## Debugging Record Video YesNo ## Customization Headless ModeRun the browser without rendering UI for faster test execution. YesNo Geolocation TestingRun the test from a different geographical location.NoneRandom CountryAustraliaBahrainBelgiumBrazilCanadaChileFranceGermanyIndiaItalyJapanNorwaySingaporeSouth AfricaSwedenSwitzerlandUnited Arab EmiratesUnited KingdomUnited States Timezone ([list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) Prerun Script ([documentation](https://testingbot.com/support/web-automate/selenium/test-options#prerun)) Upload URLs Looking for more options? See [all Puppeteer capabilities](https://testingbot.com/support/web-automate/puppeteer/options). const puppeteer = require('puppeteer'); (async () => { const capabilities = { browserName: 'chrome', browserVersion: 'latest', platformName: 'Windows 11', 'tb:options': { 'key': process.env.TB_KEY, 'secret': process.env.TB_SECRET } } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }); const page = await browser.newPage(); await page.goto('https://testingbot.com'); // Your test code here await browser.close(); })(); --- URL: https://testingbot.com/support/web-automate/puppeteer/pytest # Puppeteer & PyTest `pytest-pyppeteer` is a Python framework to use with Puppeteer. Together with `pytest-asyncio`, you can write asynchronous PyTest tests which connect to the TestingBot browser grid. Run tests in parallel on the TestingBot browser grid with PyTest, Pyppeteer and pytest-asyncio. To get started, please install these packages: pip install pytest-asyncio pyppeteer Now you're ready to use Python with Puppeteer. There's some more information about Pyppeteer on their [documentation pages](https://miyakogi.github.io/pyppeteer/). ## Example To get started, please see this simple example below. This will start a new Chrome browser in the TestingBot browser grid, and allow PyTest to control the browser via Puppeteer. import pytest import pyppeteer @pytest.mark.asyncio async def test_title(): try: browser = await pyppeteer.connect(browserWSEndpoint='wss://cloud.testingbot.com?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest') page = await browser.newPage() await page.goto('https://testingbot.com') title = await page.title() assert title == 'Cross Browser Testing and Mobile App Testing | TestingBot' await browser.close() except E: print(E) This example will open a Chrome browser, navigate to the TestingBot homepage and verify the page's title. We use `@pytest.mark.asyncio` to let PyTest know that we're using `await`. Please see [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) for more information about event loops, awaits and fixtures. ## Specifying browser and version To specify on which browser and version your PyTest + Puppeteer test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Parallel Testing with Pytest One of the great advantages of our service is that you can run multiple tests simultaneously (in parallel). This drastically shortens the total duration of your test suite, as multiple tests will run concurrently. We recommend using [pytest-parallel](https://pypi.org/project/pytest-parallel/). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/jest # Puppeteer & Jest Jest-Puppeteer allows you to run tests with Jest on browsers controlled with Puppeteer. To get started, please install these packages: npm install --save-dev jest-puppeteer puppeteer jest Next, specify these settings in your Jest configuration file (`jest.config.js`): module.exports = { rootDir: '.', testTimeout: 20000, testMatch: [ '/*.spec.js' ], preset: 'jest-puppeteer' } ## Configure Jest with Puppeteer To configure Jest Puppeteer, create a new file called `jest-puppeteer.config.js` and add this to the file: module.exports = { connect: { browserWSEndpoint: 'wss://cloud.testingbot.com?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest' } } This instructs Jest and Puppeteer to connect to the TestingBot browser grid. ## Specifying browser and version To specify on which browser and version your Jest + Puppeteer test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Run your first test To create a test, create a new file called `sample.spec.js` and add this to the file: describe('Google', () => { beforeAll(async () => { await page.goto('https://google.com') }) it('should display google text on page', async () => { await expect(page).toMatch('google') }) }) Now you can run your first test with Puppeteer on the TestingBot cloud: jest This will open Google in a Chrome browser and verify if the word 'google' is on the page. You should see something like this in your terminal after running the command: PASS ./sample.spec.js (6.503s) Google ✓ should display google text on page (81ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total This test will also appear in your [Member Dashboard](https://testingbot.com/members). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/recorder # Introduction Since Chrome 89, Chrome DevTools has an option to record/generate Puppeteer scripts by recording the actions that you do in your Chrome browser. At the time of writing this documentation, this feature is still set as a Chrome DevTools experiment. To enable the experiment, check the `Recorder` checkbox under `Settings` \> `Experiments` in your Chrome Devtools. ## Example To start recording, go to the **Sources** panel in Chrome DevTools. Then select the **Recording** tab on the left pane: ![puppeteer recording](https://testingbot.com/assets/support/puppeteer/tab-3155a96aa174390eae3f10d0f48e0b3c27ea509afbdfecf105257c6ca276593d.webp) You can now add a new recording and give it a name: Finally, you're ready to start recording. Click on the **Record** button at the bottom to start recording your interactions. Click on the Record button again to stop the recording. Chrome DevTools will generate a Puppeteer script. You can easily modify this script to have it connect to the TestingBot browser grid: ![puppeteer recording](https://testingbot.com/assets/support/puppeteer/record-5ac6d036099e2cd5ec5533006cc3eb57739bfc625fa5082dc4b95a02bc8344f3.webp) Now you can make a simple change, to have your puppeteer script point to our browser grid: ### Before const browser = await puppeteer.launch() ### After const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/chromedp # Chromedp chromedp is a golang package which allows you to automate a Chrome browser with Golang using Puppeteer syntax. To find out more about this package, please see the [chromedp documentation](https://pkg.go.dev/github.com/chromedp/chromedp). ## Installation Installing chromedp is very easy: go get -u github.com/chromedp/chromedp ## Your first Test To get started, please see this simple example: package main import ( "context" "flag" "github.com/chromedp/chromedp" "log" ) func main() { var devToolWsUrl string var title string flag.StringVar(&devToolWsUrl, "devtools-ws-url", "wss://cloud.testingbot.com?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest", "DevTools Websocket URL") flag.Parse() actxt, cancelActxt := chromedp.NewRemoteAllocator(context.Background(), devToolWsUrl) defer cancelActxt() ctxt, cancelCtxt := chromedp.NewContext(actxt) // create new tab defer cancelCtxt() // close tab afterwards if err := chromedp.Run(ctxt, chromedp.Navigate("https://testingbot.com"), chromedp.Title(&title), ); err != nil { log.Fatalf("Failed getting title of testingbot.com: %v", err) } log.Println("Got title of:", title) } This will connect with a Chrome browser running in the TestingBot cloud, go to the TestingBot homepage and print its title. ## Specifying browser and version To specify on which browser and version your Chromedp test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/options # Puppeteer Options This page lists various options that you can use to customise your Puppeteer sessions on TestingBot. The [Puppeteer Capabilities generator](https://testingbot.com/support/web-automate/puppeteer/capabilities) allows you to easily generate the necessary capabilities for your tests. ## Basic Settings ### Browser Name The name of the browser to run your Puppeteer test on. TestingBot currently supports these browserNames:. - **Chrome** - **Edge** - **Firefox** [Chrome](https://testingbot.com#)[Edge](https://testingbot.com#)[Firefox](https://testingbot.com#) const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'edge', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'firefox', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) ### Browser Version The version of the browser to run your Puppeteer test on. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Other Options: - `"version": "*"` : If you use `*` as version, TestingBot will pick a random version. - `"version": "latest"` : TestingBot will automatically take the latest version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions. For example, if the current latest Chrome version is 89 and you use `latest-2`, then the test will run on Chrome 87. - `"version": "<=16"` : TestingBot will pick a version smaller than or equal to the version you specify with `<=`. `"version": "16>="` : TestingBot will pick a version higher than or equal to the version you specify with `>=`. ### Browser Platform The OS/platform for the test VM which will run the Puppeteer test. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, platform: 'WIN10' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Possible values: - `WIN11` - `WIN10` - `TAHOE` - `SEQUOIA` - `SONOMA` - `VENTURA` - `MONTEREY` - `BIGSUR` - `LINUX` ### Make a video of your tests By default we record a video of your test, which is accessible in the member area. If you do not wish to have this, you can disable it with this option. Video should not slow down your test considerably. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', screenRecorder: false } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || boolean | true | ### Test Privacy Make the test results for this test public so that everyone can access the results. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', public: true } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || boolean | false | ### Blacklist hostnames The hostnames you specify will be pointed to localhost instead of their real destination. This means you can speed up tests by blocking third party content which you don't need and slows down your test. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', blacklist: 'site1.com,site2.com' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string (comma-separated) | ### Customize Logging By default, TestingBot records logs of all Puppeteer actions. Set this option to `false` if you don't want TestingBot to record anything (for example, if you have sensitive data). const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', recordLogs: true } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | Possible Values: || boolean | true | `true`, `false` | ### Custom Time Zones Change the Time Zone of the Virtual Machine to the Time Zone you specify. You can find a [list of timezones on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Only location names are supported (not their paths). See some examples below: const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', timeZone: 'Etc/UTC' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | Possible Values: || string | "Etc/UTC" | [List of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | ### Change Screen Resolution Will adjust the screen resolution before your test. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', 'screen-resolution': '1280x1024' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | || string | "1280x1024" | Platform | Resolutions || Windows/Linux | - 800x600 - 1024x768 - 1152x864 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1400x1050 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2560x1440 | | macOS | - 800x600 - 1024x768 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1366x768 - 1440x900 - 1600x900 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2048x1536 | | ### Geolocation Testing We provide an option where you can specify from which country you'd like to run the test from. Once you specify this option, the virtual machine we provision for your test will be configured to use a proxy in the country you specified. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', geoCountryCode: 'US' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) We currently support the following country codes: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States ### Upload This option allows you to upload a file to the test VM running the Puppeteer test. TestingBot will first download the file from the URL you specified and save it on the test VM so your test can use the file. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', upload: 'https://testingbot.com/assets/logo-head.png', uploadFilepath: '/tmp/test.png' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('http://localhost:3000') const elementHandle = await page.$('input[type=file]') await elementHandle.uploadFile('/tmp/test.png') await page.click('upload-button') await browser.close() You need specify the download URL as `upload` and use `uploadFilepath` to indicate where TestingBot needs to put the file. ### Change Test Name Add a name to this test, which will show up in our member area and API. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', name: 'First Test' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || string | unnamed test | ### Group Tests A key you can use to group certain tests in the same build (for example in Jenkins). The builds will appear in our member area. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', build: 'First Build' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string | ### Timeout Controls the timeout setting of a Puppeteer session. This setting, which is specified in seconds, controls when a session times out. A timeout occurs when a session has not received any commands from your Puppeteer test for the amount of seconds specified (default is 90 seconds). If a certain Puppeteer command takes longer than the specified setting, the session will automatically close. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', timeout: 90 } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || int (specify number of seconds) | 90 seconds | ### Idle Timeout The maximum amount of time a browser will wait before proceeding to the next step in your test. A timeout occurs when a session has not received any commands from your Puppeteer test for the xx amount of seconds specified. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET, timeout: 120000 }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || int (specify number of seconds) | 90 seconds | ### Maximum Test Duration The maximum duration for a single test. This is a safeguard to prevent bad tests from using up your credits. We generally recommend to keep tests short (less than 10 minutes). It's better to split up large tests in smaller individual tests. This keeps your tests fast and allows for more parallelization of your tests. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', maxDuration: 1800 } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || int (specify number of seconds) | 1800 seconds (30 minutes) | ### Custom Metadata Send along custom data, for example your release, server, commit hash, ... This will show up on the test detail page in the TestingBot member area. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', extra: 'Extra Information' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string | ### Startup Flags You can customize the startup flags of the browser by passing in extra flags. This is identical to passing `args` with Puppeteer. const startupFlags = [] startupFlags.push('--window-size=1280,720') startupFlags.push('--hide-scrollbars') const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com` + `?key=api_key&secret=api_secret&browserName=chrome&startupFlags=${JSON.stringify(startupFlags)}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await browser.close() ### TestingBot Tunnel You can specify the `tunnelIdentifier` to [use Puppeteer with TestingBot Tunnel](https://testingbot.com/support/web-automate/puppeteer#tunnel). const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', tunnelIdentifier: 'myPuppteerTunnel' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('http://localhost:3000') await page.screenshot({ path: 'screenshot.png' }) await browser.close() By default we support proxying these ports for localhost testing: `[443, 80, 8080, 3030, 3000, 3001, 3400]`. If you need additional ports, please pass an array of port numbers to either `localHttpPorts` or `localHttpsPorts` Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/webdriverio # Puppeteer & WebdriverIO WebdriverIO is a popular Automation Test Framework for Node.js. It has built-in support for both `WebDriver` and the `Chrome DevTools Protocol`. To get started, please install WebdriverIO: npm i @wdio/cli @wdio/local-runner Next, create a simple test suite with the command below. Follow the steps to set up a test suite. npx wdio config This will generate some files that we can use to run a Puppeteer test with WebdriverIO on the TestingBot browser grid. ## Run your first test Create a new spec file with the example code below: import { format } from 'util' import { remote } from 'webdriverio' (async () => { const browser = await remote({ capabilities: { 'wdio:devtoolsOptions': { browserWSEndpoint: format( `wss://cloud.testingbot.com?key=%s&secret=%s&browserName=chrome&browserVersion=latest`, process.env.TESTINGBOT_KEY, process.env.TESTINGBOT_SECRET ) } } }) await browser.url('https://testingbot.com') const title = await browser.getTitle() console.log(title) // returns "Cross Browser Testing and Mobile App Testing | TestingBot" await browser.deleteSession() })() You can find more information about WebdriverIO's Puppeteer support in the [WebdriverIO documentation](https://webdriver.io/docs/automationProtocols#devtools-protocol). ## Specifying browser and version To specify on which browser and version your WebdriverIO + Puppeteer test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/scraping # Puppeteer Scraping Tutorial Puppeteer is a framework that allows you to control a headless browser through scripting. The framework allows you to control a real browser, just like a normal user would. This means it's useful for both automated testing, as well as scraping. Scraping is an automated way to extract data from a website. TestingBot provides a [Scrape Function](https://testingbot.com/support/functions/scrape) to scrape a page without writing any code. ## Example To get started, please see the example below where we will scrape some text from the TestingBot website. This will start a new Chrome browser in the TestingBot browser grid and instruct the browser to navigate to the TestingBot website and scrape the text from a specific DOM element. const puppeteer = require('puppeteer') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') title = await page.evaluate(() => { return document.querySelector('body > div.main > div.hero.home > div > div > p').textContent.trim() }) console.log(title); await browser.close() Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/codeceptjs # CodeceptJS & Puppeteer CodeceptJS is an end-to-end testing framework which provides support for many automation drivers, including Puppeteer. To get started, please install these packages: npm install codeceptjs puppeteer --save To create a sample project from scratch, you can use this command: npx codeceptjs init ## Configure CodeceptJS with Puppeteer To configure CodeceptJS, please edit `codecept.conf.js` and make sure to add the `Puppeteer` helper. { // .. helpers: { Puppeteer: { url: "http://localhost", show: true, windowSize: '1200x900', chrome: { browserWSEndpoint: "wss://cloud.testingbot.com?key=YOUR_KEY&secret=YOUR_SECRET" } } } // .. } The `browserWSEndpoint` URL instructs CodeceptJS to use TestingBot's Puppeteer grid to run the tests on. ## Specifying browser and version To specify on which browser and version your CodeceptJS + Puppeteer test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Run your first test Let's create our first test, which will open the TestingBot website and check to see if the word 'TestingBot' is included on the page. Feature('Test'); Scenario('test testingbot homepage', ({ I }) => { I.amOnPage('https://testingbot.com'); I.see('TestingBot'); }); Now you can run this first test on TestingBot. npx codeceptjs run --steps Test -- test something I am on page "https://testingbot.com" I see "TestingBot" ✔ OK in 1057ms OK | 1 passed // 11s This test will appear in your [Member Dashboard](https://testingbot.com/members), together with a video of the test and any logs that were generated. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/puppeteer-parallel-testing # Parallel Testing Parallel Testing means you can run multiple tests simultaneously, with Puppeteer. It allows you to speed up your test execution, drastically shortening your total test duration time. The documentation below will show you how to run Puppeteer tests concurrently on the TestingBot browser grid, which offers over 100+ Desktop Browser combinations for Puppeteer. ## Parallel Example In the example below, we'll start various Puppeteer sessions on different browser versions, in the TestingBot cloud. const puppeteer = require('puppeteer-core') const doConnect = async (cap) => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: cap.browserName, browserVersion: cap.browserVersion, platform: cap.platform } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() } const capabilities = [ { 'browserName': 'chrome', 'browserVersion': 'latest', 'platform': 'WIN10', }, { 'browserName': 'chrome', 'browserVersion': 'latest-1', 'platform': 'LINUX', }, { 'browserName': 'edge', 'browserVersion': 'latest', 'platform': 'SEQUOIA', }] (async () => { await Promise.all( capabilities.map((cap) => doConnect(cap)) ) console.log('All tests finished!'); })(); You can use `latest` and `latest-x` to automatically run on the latest browser version. ### Queueing Depending on your account subscription, you can run multiple tests in parallel. If you exceed your maximum allocated slots, the connection will be queued until a slot frees up. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/browsers # Browser and OS versions available for Puppeteer Testing The TestingBot browser grid consists of +100 browser and OS combinations compatible with Puppeteer testing. We currently support these browser vendors with Puppeteer testing: - Chrome - Microsoft Edge - Mozilla Firefox ## Specifying browser combination To indicate on which browser you want your Puppeteer test to run, please use the following parameters as a `browserWSEndpoint` value. - `browserName` - `browserVersion` - `platform` Capability | Description | Possible Values: || `browserName` | The name of the browser | `chrome`, `edge` and `firefox` | | `browserVersion` | The version of the browser | - **Chrome:** 72 and above - **Edge:** 80 and above - **Firefox:** 110 and above You can use `latest`, `latest-1`, `latest-{x}` to test on the latest versions of the browser. | | `platform` | The Operating System where the test will run | - **Windows:** `WIN10`, `WIN11` - **macOS:** `TAHOE`, `SEQUOIA`, `SONOMA`, `VENTURA`, `MONTEREY`, `BIGSUR` | There was no release for version `82` of Chrome and Edge, so please do not specify this version. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/change-screen-resolution # Change desktop screen resolution with Puppeteer The TestingBot Desktop VMs (Windows, macOS and Linux) all support changing the screen-resolution before a test starts. We currently support the following screen resolutions: Value Type | Default Value | || string | "1280x1024" | Platform | Resolutions || Windows/Linux | - 800x600 - 1024x768 - 1152x864 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1400x1050 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2560x1440 | | macOS | - 800x600 - 1024x768 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1366x768 - 1440x900 - 1600x900 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2048x1536 | | To change the screen resolution, please specify the `screen-resolution` parameter in the `browserWSEndpoint` URL. const puppeteer = require('puppeteer-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', 'screen-resolution': '1600x900' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await page.screenshot({ path: 'screenshot.png' }) await browser.close() Changing the screen resolution does not resize the viewport. To change the viewport with Puppeteer, please use `page.setViewport`. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/test-results # Puppeteer Test Report After running a Puppeteer test on TestingBot, you can see the test result in the [TestingBot Dashboard](https://testingbot.com#dashboard) overview. You can click each test to see a [detailed overview](https://testingbot.com#single) for each specific test. By default, a Puppeteer test runs in headless mode, so no video will be available. You can change this by [enabling video recording](https://testingbot.com/support/web-automate/puppeteer/options#screenrecorder). ## The Puppeteer Dashboard The dashboard contains an overview of all your previous test runs, together with some meta-data: - **Test Name** : you can pass this name via our [REST API](https://testingbot.com/support/web-automate/puppeteer#update). - **Pass/Failure state** : you can [indicate](https://testingbot.com/support/web-automate/puppeteer#update) whether this test passed or failed. - **Browser/Device** : the browser or device that was used by the test. TestingBot provides [more than 100 different browser/OS combinations](https://testingbot.com/support/web-automate/puppeteer/browsers). - **Start Date** : when we received the call to start your test. - **Test Duration** : how long it took for your test to run. This is the actual run time, potential queueing time is not included. ## Single Puppeteer Test Detail Page For each test, we have a test detail page, which shows an overview of all the data we have: - Test Name - [session details](https://testingbot.com/support/web-automate/puppeteer/get-session-details) of the test - the pass/failure state, if you used our [REST API](https://testingbot.com/support/web-automate/puppeteer#update) - the browser/device that was used by the test - the date when the test started - how long the test took to run - logs for the test - a video recording of the test (if the test ran with [recording enabled](https://testingbot.com/support/web-automate/puppeteer/options#screenrecorder)) - the user who started the test in your team ## Viewing results without the dashboard You can [share, embed and link to builds or individual tests](https://testingbot.com/support/other/sharing) without having to visit the dashboard. This is useful when you want to create your own reporting. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/debug-tests # Debug Failing Puppeteer Tests This document will guide you in using various techniques to debug Puppeteer tests running on TestingBot. We provide several features which can help you in locating problems or debugging Puppeteer tests. ## Interactive Session Our interactive session feature allows you to pause a running Puppeteer script, and inspect the remote browser with the included Developer Tools. Simply click the **Pause Test** button on the test page while the test is running and you will be navigated to a remote browser. You can now use your mouse and keyboard to interact with the browser and debug potential issues. One important thing to remember is that you will need to add a sleep/wait in your code, so that your Puppeteer commands stop being sent when debugging. ## Video Recording Every Puppeteer test that runs on TestingBot comes with a [recorded video](https://testingbot.com/support/web-automate/puppeteer/options#screenrecorder) of the entire screen, providing you run the Puppeteer test in `headful` mode. The video is available in our member area, where you can click each Puppeteer test. Or you can [fetch the video](https://testingbot.com/support/web-automate/puppeteer/get-session-details), together with other details, through our REST API. ## Log Files For every Puppeteer test running on TestingBot, we collect the browser's log. This log can be useful for pinpointing certain issues with your script. Log files are available in our member area, where you can click each Puppeteer test. Or you can [fetch the logs](https://testingbot.com/support/web-automate/puppeteer/get-session-details), together with other details, through our REST API. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/get-session-details # Get Puppeteer Session Details When a Puppeteer test runs on TestingBot, it will generate various artifacts such as logs, video, screenshots and other files. TestingBot will save these files for later retrieval, through our member dashboard or the TestingBot [REST API](https://testingbot.com/support/api). To fetch these details through our REST API, you will need to know the unique identifier for each test. TestingBot provides a `sessionId` which you can retrieve during your test, to use in REST API calls. ### Fetch the sessionId To fetch the sessionId in your Puppeteer script, you can use the custom TestingBot command: const testingBotResponse = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'getSessionDetails'})}`) The response will contain a `sessionId`, which is a unique identifier for this test. You can then use this sessionId with the [TestingBot REST-API](https://testingbot.com/support/api). const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: 'api_key', api_secret: 'api_secret' }) const puppeteer = require('puppeteer-core') (async () => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await puppeteer.connect({ browserWSEndpoint: `wss://cloud.testingbot.com/puppeteer?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') const testingBotResponse = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'getSessionDetails'})}`) const sessionId = testingBotResponse.sessionId const testData = { "test[success]" : "1", "test[status_message]" : "test" }; await new Promise((resolve) => tb.updateTest(testData, sessionId, function(error, testDetails) { resolve(testDetails) })) console.log(`Your unique TestingBot SessionId is ${sessionId}`) await browser.close() })() Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/mark-test-status # Mark test status with Puppeteer The Puppeteer tests you run on TestingBot are using the `CDP` protocol to send commands to a remote browser. These commands instruct the remote browser what to do: click, type, resize, ... Because the logic of your test cases is inside your test script, TestingBot has no way of knowing if a test failed or passed. There is a way to send back the test status to TestingBot, by including a code snippet at the end of your test, where you know whether the test passed or failed. Below we'll go over two methods to send back the test status to TestingBot, so that we can show the pass/failure state in the dashboard and in the [TestingBot analytics](https://testingbot.com/support/analytics/guide). ## Mark test status from within a test script TestingBot has created a custom Puppeteer command which you can use in your Puppeteer scripts. You can pass in a `boolean` to indicate whether the test **passed** or **failed**. await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: { passed: false, reason: 'Title did not match' }})}`) This command will set the test as failed, with a specific reason which will be visible on the TestingBot test detail page. You can pass in the reason for a failure with the `reason` field. This command will return a JSON object with the `sessionId` of the test, which can be used with our [REST-API](https://testingbot.com/support/api). You would typically call this at the end of each test, where you know if the test failed or passed. For example, see the code snippet below where we use `chai's expect` to verify if the test passed or not. const puppeteer = require('puppeteer-core') const expect = require('chai').expect (async () => { const browser = await puppeteer.connect({ browserWSEndpoint: 'wss://cloud.testingbot.com?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&platform=WIN10' }) const page = await browser.newPage() await page.goto('https://testingbot.com/') const title = await page.title() try { expect(title).to.equal("Cross Browser Testing and Mobile App Testing. Test on web browsers, mobile emulators, simulators and physical mobile devices.", 'Expected page title is incorrect!') // This is ok, so mark the test as passed await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: true, reason: 'Title matched'}})}`) } catch { // Test failed, mark the test as failed on TestingBot await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: false, reason: 'Title did not match'}})}`) } await browser.close() })() ## Mark test status with API You can fetch the `sessionId` during an active Puppeteer test. This unique id can be used during or after the test to set the pass/fail state for the test. Marking the test as passed or failed will show the success state in the TestingBot test dashboard, on the individual test detail page and in the [TestingBot analytics](https://testingbot.com/support/analytics/guide) pages. To fetch the `sessionId`, please use the sample code below. const testingBotResponse = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'getSessionDetails'})}`) The `testingBotResponse` variable will contain a `sessionId` property which you can use: { "sessionId": "......" } With the `sessionId`, you can now mark the test as passed or failed via the [TestingBot REST-API](https://testingbot.com/support/api): curl "https://api.testingbot.com/v1/tests/:sessionId" \ -X PUT \ -d "test[success]=1" \ -u key:secret Learn more about this API call and other API calls on the TestingBot [API documentation](https://testingbot.com/support/api). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/puppeteer/browser-extension-testing # Testing Browser Extensions with Manifest V3 Testing browser extensions on Chrome with Puppeteer is possible with TestingBot. Please see the information below on how to load the extension before your test starts and how to perform UI testing with Puppeteer against your Manifest V3 extension(s). ## TestingBot Storage With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your extensions to the TestingBot servers. The advantage of this is that our test VMs can immediately download your extension from the TestingBot network, which is much faster than downloading from the public internet. The API call will return a unique identifier, similar to `tb://efe932jfk`. You can then use this identifier with the capability: `"load-extension" : "tb://..."` ## Chrome Browser Extension Testing with Puppeteer You can test your `.crx` extension by [uploading the extension](https://testingbot.com#storage) and using the URL of the extension with a `load-extension` capability. const puppeteer = require('puppeteer-core') (async () => { const tbCapabilities = { browserName: 'chrome', platform: 'WIN10', key: process.env.TB_KEY, secret: process.env.TB_SECRET, 'load-extension': 'tb://path-to-extension' } const wsEndpoint = `wss://cloud.testingbot.com?capabilities=${encodeURIComponent( JSON.stringify(tbCapabilities) )}`; const browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint }) const page = await browser.newPage() await page.goto('https://testingbot.com') // add various checks to test your extension await browser.close() })(); ### UI Testing Chrome Extensions You can test the UI and functionality of your extension in a remote Chrome browser. const puppeteer = require('puppeteer-core') (async () => { const tbCapabilities = { browserName: 'chrome', platform: 'WIN10', key: process.env.TB_KEY, secret: process.env.TB_SECRET, 'load-extension': 'tb://path-to-extension' } const wsEndpoint = `wss://cloud.testingbot.com?capabilities=${encodeURIComponent( JSON.stringify(tbCapabilities) )}`; const browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint }) const page = await browser.newPage() await page.goto('chrome-extension://lliapakmekmldfaphofjcnbccemlgeoa/src/pages/popup/index') await browser.close() })(); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright # Playwright Testing [Playwright](https://playwright.dev/) is an open-source NodeJS library developed by Microsoft for automating browsers using the DevTools protocol. Its syntax is very similar to Puppeteer. The advantages of using Microsoft Playwright is that it offers various useful features: - **auto wait** : Playwright automatically waits for elements (locators) to appear in the DOM, reducing the need for manual waiting logic. - **browser compatibility** : Playwright supports multiple browsers: Chromium (Google Chrome, Microsoft Edge, and other Chromium-based browsers), Firefox and WebKit - **fast test execution** : tests (browser automation) will run much faster than Selenium, due to improved communication standards (WebSocket). ## Installing Playwright To install Playwright, simply use `yarn` or `npm`: npm i --save playwright By default, installing Playwright will also install one or more browsers. If you only want to use the TestingBot cloud, you might consider installing Playwright without the bundled browsers, called `playwright-core`: npm i playwright-core ## Running your first Playwright test To run your first test, please use this example: [Chrome](https://testingbot.com#)[Edge](https://testingbot.com#)[Firefox](https://testingbot.com#)[WebKit](https://testingbot.com#) const playwright = require('playwright-core'); (async () => { const browser = await playwright.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); This example will start a Chrome Browser, navigate to testingbot.com and save a PNG screenshot of the webpage. const playwright = require('playwright-core'); (async () => { const browser = await playwright.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=edge&browserVersion=latest', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); This example will start a Microsoft Edge Browser, navigate to testingbot.com and save a PNG screenshot of the webpage. const playwright = require('playwright-core'); (async () => { const browser = await playwright.firefox.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=firefox&browserVersion=latest', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); This example will start a Mozilla Firefox Browser, navigate to testingbot.com and save a PNG screenshot of the webpage. const playwright = require('playwright-core'); (async () => { const browser = await playwright.webkit.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=safari&browserVersion=latest', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); This example will start a WebKit Browser, navigate to testingbot.com and save a PNG screenshot of the webpage. ## Updating your existing Playwright scripts With a Playwright test, you'll usually start a browser with `await pw.chromium.launch()` To start using our service, simply replace this line with our browser endpoint: ### Before const browser = await pw.chromium.launch(); ### After await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=edge&browserVersion=latest', }); ## Specifying browser and version To specify on which browser and version your Playwright test should run, you can include both a `browserName` and `browserVersion` in the `wsEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Updating Test Details Every Playwright test will appear in the TestingBot dashboard, by default as an unnamed test. You can specify various parameters in the `wsEndpoint` to customize this. Specify a [name](https://testingbot.com/support/web-automate/playwright/options#name), [extra (metadata) information](https://testingbot.com/support/web-automate/playwright/options#customdata) or group tests together as a [build](https://testingbot.com/support/web-automate/playwright/options#build). TestingBot has created a custom Playwright command, which you can use in your tests, to mark a test as passed or failed in the TestingBot dashboard. See the example below, where we run a Playwright script and depending on whether the test passes or fails, we send back the correct test status to TestingBot. const pw = require('playwright-core') const expect = require('chai').expect (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/') const title = await page.title() try { expect(title).to.equal("Cross Browser Testing and Mobile App Testing. Test on web browsers, mobile emulators, simulators and physical mobile devices.", 'Expected page title is incorrect!') // This is ok, so mark the test as passed await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: true, reason: 'Title matched'}})}`) } catch { // Test failed, mark the test as failed on TestingBot await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: false, reason: 'Title did not match'}})}`) } await browser.close() })() ## Integration with Playwright Test Playwright comes with its own test library: [Playwright Test](https://testingbot.com/support/web-automate/playwright/playwright-test). It is developed by Microsoft and offers a robust set of features to quickly write and run automated browser tests. Playwright test comes with a developer-friendly API that greatly simplifies creating tests. You can even [record Playwright tests with its built-in Test Generator](https://testingbot.com/support/web-automate/playwright/recorder) if you don't want to spend time writing the tests yourself. The framework comes with a lot of extra features which promote best practices: - **Page Object Models:** Group common test logic in Page Object Models to avoid code duplication and enhance the structure of your tests. This in turn simplifies test management. - **Interact with Dialogs:** Playwright can interact with dialogs such as `alert`, `confirm`, `prompt` and even `beforeunload` confirmations. - **accessibility testing:** You can use Playwright to test for various accessibility issues on your website. See the [Accessibility Testing documentation](https://playwright.dev/docs/accessibility-testing) for more information. ## Playwright and TestingBot Tunnel Using Playwright in combination with [TestingBot Tunnel](https://testingbot.com/support/tunnel) allows you to test websites behind a firewall or on your local machine with Playwright on TestingBot. ### Setup Tunnel To use TestingBot Tunnel in combination with Playwright, you first need to start the TestingBot Tunnel and pass it a `tunnelIdentifier` name of your liking. java -jar testingbot-tunnel.jar key secret -i myPlaywrightTunnel In this example, we'll start a TestingBot Tunnel with identifier **myPlaywrightTunnel**. Next, we'll need to configure our Playwright script to use the tunnel, using the same identifier. ### Setup Playwright To let Playwright know which tunnel we want to use, we need to specify the identifier from before as a parameter. Please see the example below where we pass the `tunnelIdentifier` with **myPlaywrightTunnel**. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&tunnelIdentifier=myPlaywrightTunnel', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('http://localhost:3000/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); This Playwright script will open the latest Chrome browser on the TestingBot browser grid, use the tunnel to access your localhost website and take a screenshot from that page. ### Playwright and TestingBot Tunnel Launcher [testingbot-tunnel-launcher](https://github.com/testingbot/testingbot-tunnel-launcher) is a NodeJS library which allows you to manage the tunnel from within your NodeJS script. To use it, you can install with `npm install testingbot-tunnel-launcher` and use it with Playwright: const testingbotTunnel = require('testingbot-tunnel-launcher') const pw = require('playwright-core') (async () => { const tunnel = await new Promise((resolve, reject) => { testingbotTunnel({ apiKey: 'api_key', apiSecret: 'api_secret', verbose: true, tunnelIdentifier: 'playwrightTunnel' }, function (err, tunnel) { if (err) { reject(err) return } resolve(tunnel) }) }) const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&tunnelIdentifier=playwrightTunnel', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('http://localhost:8080/') await page.screenshot({ path: 'screenshot.png' }) await browser.close() await tunnel.close() })() This example will start a new Tunnel, start a Playwright script on the latest Chrome version in TestingBot, and take a screenshot of the website running on your local computer `(http://localhost:8080)` ## Playwright Agents Playwright comes with [3 agents](https://playwright.dev/docs/test-agents) that can be used to create tests. - **planner** explores the app and produces a Markdown test plan - **generator** transforms the Markdown plan into the Playwright Test files - **healer** executes the test suite and automatically repairs failing tests, for example due to bad/missing locators To get started, use this command to initialize the agent definitions: npx playwright init-agents --loop=claude Once the tests are created, you can simply point these to use a remote TestingBot browser by replacing the `launch` command with a `connect` command, as shown in the previous sections. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/capabilities # Playwright Capabilities Generator Generate Playwright connection options for your automated tests. Choose your browser, device emulation and configuration options to get the exact code you need for your Playwright tests. [![Selenium capabilities](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)Selenium](https://testingbot.com/support/web-automate/selenium/capabilities)[![Appium capabilities](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)Appium](https://testingbot.com/support/app-automate/appium/capabilities)[![Puppeteer capabilities](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)Puppeteer](https://testingbot.com/support/web-automate/puppeteer/capabilities)[![Playwright capabilities](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)Playwright](https://testingbot.com/support/web-automate/playwright/capabilities) Browser Environment ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser Selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Resolution800x6001024x7681280x8001280x9601280x10241440x9001680x10501600x12001920x12001920x10802560x1440 ## Project Capabilities Test NameAllows you to customize the name of the test, as it will appear in the dashboard. Build NameGroup tests under the same build identifier for easy retrieval. ## Debugging Record Video YesNo ## Customization Headless ModeRun the browser without rendering UI for faster test execution. YesNo Geolocation TestingRun the test from a different geographical location.NoneRandom CountryAustraliaBahrainBelgiumBrazilCanadaChileFranceGermanyIndiaItalyJapanNorwaySingaporeSouth AfricaSwedenSwitzerlandUnited Arab EmiratesUnited KingdomUnited States Timezone ([list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)) Prerun Script ([documentation](https://testingbot.com/support/web-automate/selenium/test-options#prerun)) Upload URLs Looking for more options? See [all Playwright capabilities](https://testingbot.com/support/web-automate/playwright/options). const playwright = require('playwright-core'); (async () => { const capabilities = { browserName: 'chrome', browserVersion: 'latest', platformName: 'Windows 11', 'tb:options': { 'key': process.env.TB_KEY, 'secret': process.env.TB_SECRET } } const browser = await playwright.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); --- URL: https://testingbot.com/support/web-automate/playwright/playwright-test # Playwright Test Playwright comes with its own test-runner called Playwright Test. It is designed to make end-to-end testing easy with Playwright. More information about `@playwright/test` is available in the [Playwright documentation](https://playwright.dev/docs/test-configuration). See the TestingBot [Playwright Test Node Example repository](https://github.com/testingbot/node-playwright-test-example) for a simple example on how to run Playwright tests with TestingBot. ## Installation To get started, please install the Playwright Test package: npm i -D @playwright/test ## Configuration Next, we will need to create a [configuration file](https://playwright.dev/docs/test-configuration) so that Playwright Test knows what tests to run and what options to use. Create a file called `playwright.config.js` with the following contents: import { defineConfig } from '@playwright/test' import { getConnectWsEndpoint } from './testingbot.config' /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: './tests', /* Maximum time one test can run for. */ timeout: 30 * 1000, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ // baseURL: 'http://localhost:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, projects: [ { name: 'playwright-chrome@latest:Windows 10', use: { connectOptions: { wsEndpoint: getConnectWsEndpoint({ browserName: 'chrome', browserVersion: 'latest', platform: 'WIN10' }) } }, }, { name: 'playwright-firefox@latest:Linux', use: { connectOptions: { wsEndpoint: getConnectWsEndpoint({ browserName: 'firefox', browserVersion: 'latest', platform: 'LINUX' }) } } } ] }) You will also need to create a `testingbot.config.js` file, which will contain code to connect to our Playwright server: export function getConnectWsEndpoint(userCapabilities) { const defaultCapabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET } } const capabilities = { ...defaultCapabilities, ...userCapabilities } const connectUrl = `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` return connectUrl } You're now all set up to run your first Playwright Test on TestingBot. Let's see the [example](https://testingbot.com#example) below to run a test. ## Specifying browser and version To specify on which browser and version your Playwright test should run, you can include both a `browserName` and `browserVersion` in the `wsEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Example Test As we've [previously defined in our playwright.config.js file](https://testingbot.com#configuration), our tests should be placed in the `tests` directory. Create a new file in the `tests` directory called `sample.spec.js`: const { test, expect } = require('@playwright/test') test('Sample TestingBot test', async ({ page }, testInfo) => { try { await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionName', arguments: { name: testInfo.project.name }})}`) await page.goto('https://testingbot.com/',{ waitUntil: 'networkidle' }) await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus', arguments: { passed: true }})}`) } catch (e) { await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus', arguments: { passed: false, reason: e.message }})}`) } }) To run the test, execute this command in the directory where you placed the configuration file: npx playwright test This test will set the correct name to be shown in the TestingBot dashboard, navigate with the remote browser to the TestingBot homepage and then set the test as passed. ## Reports There are various [Test Reporters](https://playwright.dev/docs/test-reporters) that Playwright offers, which you can change in the [configuration file](https://testingbot.com#configuration). For every test that runs on TestingBot, you will receive a video of the test, generated logs and other meta-data. ## Other Options You can set various [Timeout options](https://playwright.dev/docs/test-timeouts), use [annotations](https://playwright.dev/docs/test-annotations) and set up [setup and teardown scripts](https://playwright.dev/docs/test-global-setup-teardown). The global setup and teardown scripts can be used to start (and stop) a [TestingBot Tunnel](https://testingbot.com/support/tunnel), which allows you to test on websites that are not publicly available. An example of a setup script: const testingbotTunnel = require('testingbot-tunnel-launcher') module.exports = async () => { await new Promise((resolve, reject) => { testingbotTunnel({ apiKey: process.env.TB_KEY, apiSecret: process.env.TB_SECRET, verbose: true }, function (err, tunnel) { if (err) { console.error(err.message) return reject(err) } resolve() }) }) } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/visual-regression-testing # Playwright Visual Regression Testing Playwright Test supports [visual comparisons](https://playwright.dev/docs/test-snapshots), where it will take a screenshot of a page and then compare it with a 'golden image'. A golden image is a snapshot of what the correct visual layout should be. Once you have a snapshot, your test can check if the layout still matches the one saved in the snapshot. If it does not match, your test will fail. To get started, let's create a test called `playwright_test.spec.js` with the following contents: const { test, expect } = require('@playwright/test') test('should add an item', async ({ page }) => { await page.goto('https://testingbot.com') const title = await page.title() await expect(page).toHaveScreenshot() }) Next, make sure you've created a [playwright.config.js configuration file](https://testingbot.com/support/web-automate/playwright/playwright-test#configuration), which contains details such as: - How to connect to the TestingBot browser grid - On which remote browsers this visual test should run To start the test, please run this command: npx playwright test The first run will fail, because there's no 'golden image' yet. When you run the test again, Playwright will take a new screenshot and compare it with the golden snapshot. You can [configure the threshold](https://github.com/mapbox/pixelmatch#api), `maxDiffPixels` to your liking: await expect(page).toHaveScreenshot({ maxDiffPixels: 100 }) ## Masked Screenshots Playwright provides the option to mask any specific locator when taking a screenshot. This is useful if you want to do regression testing, and you know that a specific part of the page has content that might cause the test to fail or is not important for your test. For example an ad, random list, or anything else that should not impact your visual comparison test. Simply find one or more locators of elements you want to hide: const mask_locator = page.locator("#random-image") Finally, take a screenshot but mask the locators: await page.screenshot({ path: 'masked.png', mask: [mask_locator] }) Below is an example of a screenshot with a masked locator: ![Playwright masked screenshot](https://testingbot.com/assets/support/playwright/masked-166e5ef9ecd63165a953ed564e770afd37b47ff4e280f7e9ba12665244af9c81.png) ## Text and binary snapshots Next to comparing images, Playwright also supports comparing text or other (binary) data, through snapshots. The example below shows how to compare the text of a DOM element to make sure it matches its snapshot. const { test, expect } = require('@playwright/test') test('example test', async ({ page }) => { await page.goto('https://testingbot.com') expect(await page.textContent('body > div.main > div.hero.home > div > div > p')).toMatchSnapshot('hero.txt') }) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/performance # Measuring Performance with Playwright Today, it is more important than ever to make sure your website loads fast. The speed of your website matters for a lot of reasons: - Faster websites receive more organic search engine traffic - Improved user experiences cause an increase in online sales - Less frustration when using your product Making your webpages faster takes a lot of effort and requires measurements to figure out what to optimise and how to optimise. Modern browsers expose a lot of [performance metrics](https://web.dev/metrics/) that can help you with determining what to improve and which changes to make. Playwright can help with identifying reasons that cause slowdowns, by querying the various performance related APIs that browsers provide. Chromium browsers for example provide a rich set of metrics, called [Web Vitals metrics](https://web.dev/vitals/). These metrics include Time to First Byte (TTFB), Total Blocking Time (TBT) and First Contentful Paint (FCP), which are good user experience indicators and worth monitoring in your tests. ## Navigation and Resource Timing API The [Navigation Timing API](https://developer.mozilla.org/en-US/docs/Web/API/Navigation_timing_API) allows you to retrieve all events and timings related to pageload times. The response contains various interesting fields, such as `domComplete` time, `duration` and `connectEnd`. You can use these metrics in your tests, to detect performance regressions for each webpage you are testing. ### Performance Budget Your Playwright tests could use a performance budget, where you want to make sure that the performance of a webpage does not go below a specific standard that you set. For example, see the following Playwright code where we detect the `domComplete`, if it goes below a threshold we want to fail the testcase, alerting us of a possible performance regression. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/'); const navigationTimingJson = await page.evaluate(() => JSON.stringify(performance.getEntriesByType('navigation')) ) const navigationTiming = JSON.parse(navigationTimingJson) if (navigationTiming[0].domComplete > 2000) { console.error('ERROR: domComplete above 2 seconds') } await browser.close() })() ### Resource Timing API The [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Resource_timing) provides a way to get timing information for specific resources on the page. For example, you can check how quickly an image loaded on your page. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/'); const resourceTimingJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType('resource')) ) const resourceTiming = JSON.parse(resourceTimingJson) const logoResourceTiming = resourceTiming.find((element) => element.name.includes('.webp') ) console.log(logoResourceTiming) await browser.close() })() ## Paint Timing API You can use the [Paint Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformancePaintTiming) to retrieve timings on First Paint (FP) and First Contentful Paint (FCP). const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/'); const paintTimingJson = await page.evaluate(() => JSON.stringify(window.performance.getEntriesByType('paint')) ) const paintTiming = JSON.parse(paintTimingJson) console.log(paintTiming) await browser.close() })() ## Layout Instability API The Layout Instability API provides information regarding layout shifts. Layout shifts happen when the layout of your webpage changes during the loading of the page. You can use this API to evaluate the [Core Web Vital Cumulative Layout Shift](https://web.dev/cls/) (CLS). const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/'); const cumulativeLayoutShift = await page.evaluate(() => { return new Promise((resolve) => { let CLS = 0 new PerformanceObserver((l) => { const entries = l.getEntries() entries.forEach(entry => { if (!entry.hadRecentInput) { CLS += entry.value } }) resolve(CLS) }).observe({ type: 'layout-shift', buffered: true }) }) }) console.log(parseFloat(cumulativeLayoutShift)) await browser.close() })() ## Long Task API The [Long Task API](https://developer.mozilla.org/en-US/docs/Web/API/Long_Tasks_API) returns a list of Javascript executions that take more than 50 milliseconds to complete (block the UI thread). You can use this API to calculate the [Total Blocking Time](https://web.dev/tbt/) (TBT). To calculate the TBT value, we need to use a `PerformanceObserver`. This will observe longtasks entries and make a sum of the differences to the maximal JavaScript execution time of 50 milliseconds. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/'); const totalBlockingTime = await page.evaluate(() => { return new Promise((resolve) => { let totalBlockingTime = 0 new PerformanceObserver(function (list) { const perfEntries = list.getEntries() for (const perfEntry of perfEntries) { totalBlockingTime += perfEntry.duration - 50 } resolve(totalBlockingTime) }).observe({ type: 'longtask', buffered: true }) // Resolve promise if there haven't been any long tasks setTimeout(() => resolve(totalBlockingTime), 5000) }) }) console.log(parseFloat(totalBlockingTime)) await browser.close() })() ## Chrome DevTools Performance The Chrome DevTools Protocol provides many great performance tools that you can use. You can check the [DevTools Protocol documentation](https://chromedevtools.github.io/devtools-protocol/) for an extensive overview of all the possibilities. One of the examples you can use with DevTools is throttling the network. To use this, you need to send the `Network.emulateNetworkConditions` command. The syntax to connect to TestingBot is slightly different, as we now need to use `connectOverCDP`. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connectOverCDP({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = browser.contexts()[0] const page = context.pages()[0] const client = await context.newCDPSession(page) await client.send('Network.enable') await client.send('Network.emulateNetworkConditions', { offline: false, downloadThroughput: (5 * 1024 * 1024) / 8, uploadThroughput: (4 * 1024 * 1024) / 8, latency: 30 }) await page.goto('https://testingbot.com/'); await browser.close() })() Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/pytest # Playwright & PyTest To use PyTest with Playwright, we'll need a Python library that automates via Playwright. Microsoft's [playwright-python](https://github.com/microsoft/playwright-python) library provides a Python library which does Automation via Playwright. To get started, please install these packages: pip install pytest-playwright playwright install Now you're ready to use Python with Playwright. You can take a look at the [playwright-python examples](https://github.com/microsoft/playwright-python#usage) on how to do this. ## Example To get started, please see this simple example below. This will start a new Chrome browser in the TestingBot browser grid, and allow PyTest to control the browser via Playwright. import pytest from playwright.sync_api import Playwright @pytest.fixture def browser(playwright: Playwright): return playwright.chromium.connect(ws_endpoint = 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', timeout=90000) def test_title(browser): page = browser.new_page() page.goto('https://testingbot.com') assert page.title() == 'TestingBot: Cross Browser Testing and Mobile App Testing' browser.close() This example will open a Chrome browser, navigate to the TestingBot homepage and verify the page's title. ## Parallel Testing with PyTest One of the great advantages of our service is that you can run multiple tests simultaneously (in parallel). This drastically shortens the total duration of your test suite, as multiple tests will run concurrently. We recommend using [pytest-parallel](https://pypi.org/project/pytest-parallel/). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/robotframework # Robot Framework & Playwright [Browser Library](https://robotframework-browser.org/) allows you to run Playwright tests with Robot Framework. By using TestingBot, you will be able to run Robot tests using Playwright on TestingBot's browser grid. The advantage is that you do not have to set up and maintain a fleet of different browsers, versions and operating systems. Another advantage is that you can run multiple tests, in parallel, on TestingBot's grid. ## Example Below is an example on how to connect to the TestingBot browser grid, using Browser Library's [Connect To Browser](https://marketsquare.github.io/robotframework-browser/Browser.html#Connect%20To%20Browser). To run the test, simply save it in a file (for example `test.robot`) and call `python -m robot test.robot` from the command line. ***Settings*** Library Browser Test Setup Setup TestingBot ***Variables*** &{desiredCapabilities} platform=WIN10 ... browserName=chrome ... key=add-your-TestingBot-key ... secret=add-your-TestingBot-secret ***Keywords*** Setup TestingBot ${TBCAPS} Evaluate urllib.parse.quote( json.dumps(${desiredCapabilities}) ) Connect To Browser wsEndpoint=wss://cloud.testingbot.com/playwright?capabilities=${TBCAPS} ***Test Cases*** Playwright Test New Page https://playwright.dev/ Get Title matches Playwright Get Attribute "Get started" href == /docs/intro Click "Get started" Get Url matches .*intro This example will open a Chrome browser using Playwright on TestingBot, navigate to the Playwright website and do some verifications. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/jest # Playwright & Jest Jest-Playwright allows you to run tests with Jest on browsers controlled with Playwright. To get started, please install the package: npm init && npm install -D jest jest-playwright-preset playwright Next, specify these settings in your Jest configuration file (`jest.config.js`): module.exports = { rootDir: '.', testTimeout: 20000, testMatch: [ '/*.spec.js' ], preset: 'jest-playwright-preset' } ## Configure Jest-Playwright To configure Jest Playwright, please create a new file called `jest-playwright.config.js` and add this to the file: module.exports = { connectBrowserApp: { wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=edge&browserVersion=latest' } } This instructs Jest Playwright to connect to the TestingBot browser grid and use the latest Edge browser. ## Run your first test To create a test, create a new file called `sample.spec.js` and add this to the file: describe('Google', () => { beforeAll(async () => { await page.goto('https://google.com') }) it('should display google text on page', async () => { await expect(page).toMatch('google') }) }) Now you can run your first test with Playwright on the TestingBot cloud: jest This will open Google in an Edge browser and verify if the word 'google' is on the page. You should see something like this in your terminal after running the command: PASS ./sample.spec.js (6.503s) Google ✓ should display google text on page (81ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total This test will also appear in your [Member Dashboard](https://testingbot.com/members). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/mocha # Playwright & Mocha [Mocha](https://mochajs.org/) is a popular Javascript/NodeJS test runner, which is great for E2E testing. See the example below on how to use Mocha and Playwright to run tests on the TestingBot browser grid. ## Installation To get started, please install these packages: npm i mocha chai playwright-core Now you can create a basic test script. Usually, you'll create these in a `test` folder, with a filename ending in `.spec.js`: const pw = require('playwright-core') const chai = require('chai') const expect = chai.expect let page, browser, context describe('Sample Test', () => { beforeEach(async function() { this.timeout(35000) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) context = await browser.newContext() page = await context.newPage() }) afterEach(async function() { await page.screenshot({ path: `${this.currentTest.title.replace(/\s+/g, '_')}.png` }) await browser.close() }) it('Checks the title of the page', async() => { await page.goto('https://testingbot.com/'); const title = await page.title() expect(title).to.equal('TestingBot: Cross Browser Testing and Mobile App Testing') }) }) This example will use Playwright to connect to a Chrome browser in the TestingBot cloud. It will open the TestingBot website, retrieve the title of the page and verify with `expect` if the title is correct. Chai is used to do assertions, this is a popular assertion library, allowing you to use either `expect`, `should` and `assert`, depending on your preferences. After each test, we'll take a screenshot and close the browser (see the `afterEach` part of the example code). ## Parallel Testing with Mocha One of the great advantages of the TestingBot service is that you can run multiple tests simultaneously. This drastically shortens the total duration of your test suite, as multiple tests will run concurrently. By default, Mocha does not run multiple test files in parallel. To achieve parallelism, you can use `mocha-parallel-tests`, which is an NPM package that will run each of your test files in a separate process. npm i mocha-parallel-tests Now you can create multiple `test/*.spec.js` files with different tests: `test/test-one.spec.js`: const pw = require('playwright-core') const chai = require('chai') const expect = chai.expect let page, browser, context describe('Sample Test', () => { beforeEach(async function() { this.timeout(35000) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) context = await browser.newContext() page = await context.newPage() }) afterEach(async function() { await page.screenshot({ path: `${this.currentTest.title.replace(/\s+/g, '_')}.png` }) await browser.close() }) it('Checks the title of the page', async() => { await page.goto('https://testingbot.com/'); const title = await page.title() expect(title).to.equal('TestingBot: Cross Browser Testing and Mobile App Testing') }) }) `test/test-two.spec.js`: const pw = require('playwright-core') const chai = require('chai') const expect = chai.expect let page, browser, context describe('Sample Test', () => { beforeEach(async function() { this.timeout(35000) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) context = await browser.newContext() page = await context.newPage() }) afterEach(async function() { await page.screenshot({ path: `${this.currentTest.title.replace(/\s+/g, '_')}.png` }) await browser.close() }) it('Checks the title of the page', async() => { await page.goto('https://testingbot.com/pricing'); const title = await page.title() expect(title).to.equal('Cross Browser Testing - Prices and plans available for test online.') }) }) To run these 2 test files simultaneously, please run this command: mocha-parallel-tests test/*.spec.js You should see output similar to: Sample Test ✓ Checks the title of the page (798ms) Sample Test ✓ Checks the title of the page (921ms) 2 passing (26s) Depending on how many tests you run in parallel, you can drastically shorten your total test duration, and get faster feedback from your tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/java # Playwright & Java Playwright for Java provides a powerful API for browser automation that can be used for end-to-end testing. See the example below on how to use Java with Playwright to run tests on the TestingBot browser grid. More information about Playwright for Java can be found on the [Playwright Java documentation](https://playwright.dev/java/docs/intro). ## Installation To get started, add the Playwright dependency to your Maven project: com.microsoft.playwright playwright 1.53.0 Or if you're using Gradle: implementation 'com.microsoft.playwright:playwright:1.53.0' Now you can create a basic test script. Below is an example using JUnit 5: package com.example; import com.google.gson.JsonObject; import com.microsoft.playwright.*; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.assertEquals; class PlaywrightTest { static Playwright playwright; static Browser browser; Page page; @BeforeAll static void launchBrowser() { // Create the capabilities object with authentication information JsonObject capabilities = new JsonObject(); JsonObject tbOptions = new JsonObject(); tbOptions.addProperty("key", "YOUR_KEY"); tbOptions.addProperty("secret", "YOUR_SECRET"); capabilities.add("tb:options", tbOptions); capabilities.addProperty("browserName", "chrome"); capabilities.addProperty("browserVersion", "latest"); capabilities.addProperty("platform", "WIN10"); // Create a custom browser type to connect to TestingBot playwright = Playwright.create(); String wsEndpoint = "wss://cloud.testingbot.com/playwright?capabilities=" + java.net.URLEncoder.encode(capabilities.toString(), java.nio.charset.StandardCharsets.UTF_8); browser = playwright.chromium().connect(new BrowserType.ConnectOptions() .setWsEndpoint(wsEndpoint)); } @AfterAll static void closeBrowser() { if (playwright != null) { playwright.close(); playwright = null; } } @BeforeEach void createContextAndPage() { BrowserContext context = browser.newContext(); page = context.newPage(); } @AfterEach void closeContext() { if (page != null) { // Take a screenshot after the test page.screenshot(new Page.ScreenshotOptions() .setPath(java.nio.file.Paths.get("screenshot-" + java.util.UUID.randomUUID() + ".png"))); page.context().close(); page = null; } } @Test void shouldCheckPageTitle() { page.navigate("https://testingbot.com/"); String title = page.title(); assertEquals("TestingBot: Cross Browser Testing and Mobile App Testing", title); } } This example will use Playwright to connect to a Chrome browser in the TestingBot cloud. It will open the TestingBot website, retrieve the title of the page and verify with JUnit assertions if the title is correct. You can also use test frameworks like TestNG with Playwright, following a similar approach. Just adapt the test annotations according to your preferred test framework. After each test, we'll take a screenshot and close the browser context to clean up resources. ## Parallel Testing with Java One of the great advantages of the TestingBot service is that you can run multiple tests simultaneously. This drastically shortens the total duration of your test suite, as multiple tests will run concurrently. Here's how you can set up parallel test execution using JUnit 5: package com.example; import com.google.gson.JsonObject; import com.microsoft.playwright.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; // Enable parallel execution for the class @Execution(ExecutionMode.CONCURRENT) class ParallelPlaywrightTests { // Helper method to set up the browser private Browser setupBrowser(String browserName) { // Create capabilities JsonObject capabilities = new JsonObject(); JsonObject tbOptions = new JsonObject(); tbOptions.addProperty("key", "YOUR_KEY"); tbOptions.addProperty("secret", "YOUR_SECRET"); capabilities.add("tb:options", tbOptions); capabilities.addProperty("browserName", browserName); capabilities.addProperty("browserVersion", "latest"); // Create the playwright instance Playwright playwright = Playwright.create(); String wsEndpoint = "wss://cloud.testingbot.com/playwright?capabilities=" + java.net.URLEncoder.encode(capabilities.toString(), java.nio.charset.StandardCharsets.UTF_8); // Connect based on browser type BrowserType browserType; if (browserName.equals("chrome")) { browserType = playwright.chromium(); } else if (browserName.equals("firefox")) { browserType = playwright.firefox(); } else if (browserName.equals("webkit")) { browserType = playwright.webkit(); } else { throw new IllegalArgumentException("Unsupported browser: " + browserName); } return browserType.connect(new BrowserType.ConnectOptions() .setWsEndpoint(wsEndpoint)); } @Test void testHomepageInChrome() { // Each test manages its own browser instance try (Browser browser = setupBrowser("chrome")) { BrowserContext context = browser.newContext(); Page page = context.newPage(); try { page.navigate("https://testingbot.com/"); String title = page.title(); assertEquals("TestingBot: Cross Browser Testing and Mobile App Testing", title); page.screenshot(new Page.ScreenshotOptions() .setPath(java.nio.file.Paths.get("chrome-homepage.png"))); } finally { context.close(); } } } @Test void testPricingPageInFirefox() { // Each test manages its own browser instance try (Browser browser = setupBrowser("firefox")) { BrowserContext context = browser.newContext(); Page page = context.newPage(); try { page.navigate("https://testingbot.com/pricing"); String title = page.title(); assertEquals("Cross Browser Testing - Prices and plans available for test online.", title); page.screenshot(new Page.ScreenshotOptions() .setPath(java.nio.file.Paths.get("firefox-pricing.png"))); } finally { context.close(); } } } } To enable parallel execution with JUnit 5, you need to configure it in your `junit-platform.properties` file: junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.mode.default=concurrent junit.jupiter.execution.parallel.mode.classes.default=concurrent With TestNG, you can configure parallel execution in your test XML file: The examples above demonstrate how to run multiple tests concurrently against different browsers on the TestingBot infrastructure. Each test manages its own browser instance, allowing multiple tests to run in parallel. Depending on how many tests you run in parallel, you can drastically shorten your total test duration and get faster feedback from your tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/dotnet # Playwright & .NET Playwright for .NET provides a powerful API for browser automation that can be used for end-to-end testing with C# and other .NET languages. See the example below on how to use .NET with Playwright to run tests on the TestingBot browser grid. More information about Playwright for .NET can be found on the [Playwright .NET documentation](https://playwright.dev/dotnet/docs/intro). ## Installation To get started with Playwright for .NET, you'll need to install the relevant NuGet packages for your preferred test framework: [MSTest](https://testingbot.com#)[NUnit](https://testingbot.com#)[xUnit](https://testingbot.com#) To install the Playwright NuGet packages for MSTest, run the following commands in your terminal: dotnet new mstest dotnet add package Microsoft.Playwright dotnet add package Microsoft.Playwright.MSTest dotnet build pwsh bin/Debug/net8.0/playwright.ps1 install On macOS/Linux, use: playwright install To install the Playwright NuGet packages for NUnit, run the following commands in your terminal: dotnet new nunit dotnet add package Microsoft.Playwright dotnet add package Microsoft.Playwright.NUnit dotnet build pwsh bin/Debug/net8.0/playwright.ps1 install On macOS/Linux, use: playwright install To install the Playwright NuGet packages for xUnit, run the following commands in your terminal: dotnet new xunit dotnet add package Microsoft.Playwright dotnet build pwsh bin/Debug/net8.0/playwright.ps1 install On macOS/Linux, use: playwright install Note that there is no specific Microsoft.Playwright.xUnit package, but you can still use Playwright with xUnit. ### Code Generation Playwright provides a powerful code generation tool that helps you quickly create test scripts by recording your interactions with the browser. To use it, run the following command: pwsh bin/Debug/net8.0/playwright.ps1 codegen https://testingbot.com On macOS/Linux, use: playwright codegen https://testingbot.com This will open a browser window where you can interact with the webpage, and Playwright will generate C# code based on your actions. You can then copy this code and use it as a starting point for your tests. ### Running Tests To run your tests, use the standard `dotnet test` command: dotnet test You can also run specific test classes or methods: dotnet test --filter "FullyQualifiedName=PlaywrightTests.PlaywrightTestingBotTest" [NUnit](https://testingbot.com#)[MSTest](https://testingbot.com#)[xUnit](https://testingbot.com#) Example using NUnit: using System; using System.Text.Json.Nodes; using System.Threading.Tasks; using System.Web; using Microsoft.Playwright; using Microsoft.Playwright.NUnit; using NUnit.Framework; namespace PlaywrightTests { [Parallelizable(ParallelScope.Self)] public class PlaywrightTestingBotTest : PageTest { private IBrowser _browser; private IBrowserContext _context; private IPage _page; [SetUp] public async Task SetupTestAsync() { // Create the capabilities object with authentication information var capabilities = new JsonObject { ["browserName"] = "chrome", ["browserVersion"] = "latest", ["platform"] = "WIN10", ["tb:options"] = new JsonObject { ["key"] = "YOUR_KEY", ["secret"] = "YOUR_SECRET" } }; // Create the playwright instance var playwright = await Playwright.CreateAsync(); // Connect to TestingBot var wsEndpoint = $"wss://cloud.testingbot.com/playwright?capabilities={HttpUtility.UrlEncode(capabilities.ToJsonString())}"; _browser = await playwright.Chromium.ConnectAsync(new BrowserTypeConnectOptions { WsEndpoint = wsEndpoint }); // Create a context and page _context = await _browser.NewContextAsync(); _page = await _context.NewPageAsync(); } [TearDown] public async Task TearDownTestAsync() { if (_page != null) { // Take a screenshot at the end of the test await _page.ScreenshotAsync(new PageScreenshotOptions { Path = $"screenshot-{Guid.NewGuid()}.png" }); await _context?.CloseAsync(); await _browser?.CloseAsync(); } } [Test] public async Task ShouldCheckPageTitle() { await _page.GotoAsync("https://testingbot.com/"); var title = await _page.TitleAsync(); Assert.AreEqual("TestingBot: Cross Browser Testing and Mobile App Testing", title); } } } Example using MSTest: using System; using System.Text.Json.Nodes; using System.Threading.Tasks; using System.Web; using Microsoft.Playwright; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace PlaywrightTests { [TestClass] public class PlaywrightTestingBotTest { private static IPlaywright _playwright; private IBrowser _browser; private IBrowserContext _context; private IPage _page; [TestInitialize] public async Task TestInitialize() { // Create the capabilities object with authentication information var capabilities = new JsonObject { ["browserName"] = "chrome", ["browserVersion"] = "latest", ["platform"] = "WIN10", ["tb:options"] = new JsonObject { ["key"] = "YOUR_KEY", ["secret"] = "YOUR_SECRET" } }; // Create the playwright instance _playwright = await Playwright.CreateAsync(); // Connect to TestingBot var wsEndpoint = $"wss://cloud.testingbot.com/playwright?capabilities={HttpUtility.UrlEncode(capabilities.ToJsonString())}"; _browser = await _playwright.Chromium.ConnectAsync(new BrowserTypeConnectOptions { WsEndpoint = wsEndpoint }); // Create a context and page _context = await _browser.NewContextAsync(); _page = await _context.NewPageAsync(); } [TestCleanup] public async Task TestCleanup() { if (_page != null) { // Take a screenshot at the end of the test await _page.ScreenshotAsync(new PageScreenshotOptions { Path = $"screenshot-{Guid.NewGuid()}.png" }); await _context?.CloseAsync(); await _browser?.CloseAsync(); _playwright.Dispose(); } } [TestMethod] public async Task ShouldCheckPageTitle() { await _page.GotoAsync("https://testingbot.com/"); var title = await _page.TitleAsync(); Assert.AreEqual("TestingBot: Cross Browser Testing and Mobile App Testing", title); } } } Example using xUnit: using System; using System.Text.Json.Nodes; using System.Threading.Tasks; using System.Web; using Microsoft.Playwright; using Xunit; namespace PlaywrightTests { public class PlaywrightTestingBotTest : IAsyncLifetime { private IPlaywright _playwright; private IBrowser _browser; private IBrowserContext _context; private IPage _page; public async Task InitializeAsync() { // Create the capabilities object with authentication information var capabilities = new JsonObject { ["browserName"] = "chrome", ["browserVersion"] = "latest", ["platform"] = "WIN10", ["tb:options"] = new JsonObject { ["key"] = "YOUR_KEY", ["secret"] = "YOUR_SECRET" } }; // Create the playwright instance _playwright = await Playwright.CreateAsync(); // Connect to TestingBot var wsEndpoint = $"wss://cloud.testingbot.com/playwright?capabilities={HttpUtility.UrlEncode(capabilities.ToJsonString())}"; _browser = await _playwright.Chromium.ConnectAsync(new BrowserTypeConnectOptions { WsEndpoint = wsEndpoint }); // Create a context and page _context = await _browser.NewContextAsync(); _page = await _context.NewPageAsync(); } public async Task DisposeAsync() { if (_page != null) { // Take a screenshot at the end of the test await _page.ScreenshotAsync(new PageScreenshotOptions { Path = $"screenshot-{Guid.NewGuid()}.png" }); await _context?.CloseAsync(); await _browser?.CloseAsync(); _playwright.Dispose(); } } [Fact] public async Task ShouldCheckPageTitle() { await _page.GotoAsync("https://testingbot.com/"); var title = await _page.TitleAsync(); Assert.Equal("TestingBot: Cross Browser Testing and Mobile App Testing", title); } } } This example will use Playwright to connect to a Chrome browser in the TestingBot cloud. It will open the TestingBot website, retrieve the title of the page and verify if the title is correct. You can also use test frameworks like MSTest or xUnit with Playwright, following a similar approach. Just adapt the test attributes according to your preferred test framework. After each test, we'll take a screenshot and close the browser context to clean up resources. ## Parallel Testing with .NET One of the great advantages of the TestingBot service is that you can run multiple tests simultaneously. This drastically shortens the total duration of your test suite, as multiple tests will run concurrently. Here's how you can set up parallel test execution using NUnit: using System; using System.Text.Json.Nodes; using System.Threading.Tasks; using System.Web; using Microsoft.Playwright; using NUnit.Framework; namespace PlaywrightTests { [TestFixture] [Parallelizable(ParallelScope.All)] // Enable parallel execution public class ParallelPlaywrightTests { // Helper method to set up the browser private async Task SetupBrowserAsync(string browserName) { // Create capabilities var capabilities = new JsonObject { ["browserName"] = browserName, ["browserVersion"] = "latest", ["tb:options"] = new JsonObject { ["key"] = "YOUR_KEY", ["secret"] = "YOUR_SECRET" } }; // Create the playwright instance var playwright = await Playwright.CreateAsync(); // Determine which browser type to use IBrowserType browserType; switch (browserName.ToLower()) { case "chrome": browserType = playwright.Chromium; break; case "firefox": browserType = playwright.Firefox; break; case "webkit": case "safari": browserType = playwright.Webkit; break; default: throw new ArgumentException($"Unsupported browser: {browserName}"); } // Connect to TestingBot var wsEndpoint = $"wss://cloud.testingbot.com/playwright?capabilities={HttpUtility.UrlEncode(capabilities.ToJsonString())}"; return await browserType.ConnectAsync(new BrowserTypeConnectOptions { WsEndpoint = wsEndpoint }); } [Test] public async Task TestHomepageInChrome() { // Each test manages its own browser instance using var playwright = await Playwright.CreateAsync(); var browser = await SetupBrowserAsync("chrome"); try { var context = await browser.NewContextAsync(); var page = await context.NewPageAsync(); try { await page.GotoAsync("https://testingbot.com/"); var title = await page.TitleAsync(); Assert.AreEqual("TestingBot: Cross Browser Testing and Mobile App Testing", title); await page.ScreenshotAsync(new PageScreenshotOptions { Path = "chrome-homepage.png" }); } finally { await context.CloseAsync(); } } finally { await browser.CloseAsync(); } } [Test] public async Task TestPricingPageInFirefox() { // Each test manages its own browser instance using var playwright = await Playwright.CreateAsync(); var browser = await SetupBrowserAsync("firefox"); try { var context = await browser.NewContextAsync(); var page = await context.NewPageAsync(); try { await page.GotoAsync("https://testingbot.com/pricing"); var title = await page.TitleAsync(); Assert.AreEqual("Cross Browser Testing - Prices and plans available for test online.", title); await page.ScreenshotAsync(new PageScreenshotOptions { Path = "firefox-pricing.png" }); } finally { await context.CloseAsync(); } } finally { await browser.CloseAsync(); } } } } To enable parallel execution with NUnit, add the following to your `NUnit.runsettings` file: 4 For MSTest, you can configure parallel execution in your `.runsettings` file: 4 ClassLevel The examples above demonstrate how to run multiple tests concurrently against different browsers on the TestingBot infrastructure. Each test manages its own browser instance, allowing multiple tests to run in parallel. Depending on how many tests you run in parallel, you can drastically shorten your total test duration and get faster feedback from your tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/options # Playwright Options This page lists various options that you can use to customise your Playwright sessions on TestingBot. The [Playwright Capabilities generator](https://testingbot.com/support/web-automate/playwright/capabilities) allows you to easily generate the necessary capabilities for your tests. ## Basic Settings ### Browser Name The name of the browser to run your Playwright test on. TestingBot currently supports these browserNames: - **Chrome** - **Edge** - **Firefox** - **Safari (WebKit)** [Chrome](https://testingbot.com#)[Edge](https://testingbot.com#)[Firefox](https://testingbot.com#)[WebKit](https://testingbot.com#) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await playwright.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'edge', browserVersion: 'latest' } const browser = await playwright.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'firefox', browserVersion: 'latest' } const browser = await playwright.firefox.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'safari', browserVersion: 'latest' } const browser = await playwright.webkit.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) ### Browser Version The version of the browser to run your Playwright test on. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. Other Options: - `"version": "*"` : If you use `*` as version, TestingBot will pick a random version. - `"version": "latest"` : TestingBot will automatically take the latest version. You can also use `latest-1`, `latest-2`, ... to test on the next most recent versions. For example, if the current latest Chrome version is 89 and you use `latest-2`, then the test will run on Chrome 87. - `"version": "<=16"` : TestingBot will pick a version smaller than or equal to the version you specify with `<=`. `"version": ">=16"` : TestingBot will pick a version higher than or equal to the version you specify with `>=`. ### Browser Platform The OS/platform for the test VM which will run the Playwright test. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', platform: 'WIN10' } const browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Possible values: - `WIN11` - `WIN10` - `LINUX` - `TAHOE` - `SEQUOIA` - `VENTURA` - `MONTEREY` - `BIGSUR` ### Make a video of your tests By default we record a video of your test, which is accessible in the member area. If you do not wish to have this, you can disable it with this option. Video will not slow down your test considerably. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', screenRecorder: false } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || boolean | `true` | ### Test Privacy Make the test results for this test public so that everyone can access the results. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', public: true } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || boolean | `false` | ### Blacklist hostnames The hostnames you specify will be pointed to localhost instead of their real destination. This means you can speed up tests by blocking third party content which you don't need and slows down your test. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', blacklist: 'site1.com,site2.com' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string (comma-separated) | ### Customize Logging By default, TestingBot records logs of all Playwright actions. Set this option to `false` if you don't want TestingBot to record anything (for example, if you have sensitive data). const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', recordLogs: true } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | Possible Values: || boolean | `true` | `true`, `false` | ### Custom Time Zones Change the Time Zone of the Virtual Machine to the Time Zone you specify. You can find a [list of timezones on Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Only location names are supported (not their paths). See some examples below: const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', timeZone: 'Etc/UTC' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | Possible Values: || string | "Etc/UTC" | [List of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | ### Change Screen Resolution Will adjust the screen resolution before your test. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', 'screen-resolution': '1280x1024' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value | || string | "1280x1024" | Platform | Resolutions || Windows/Linux | - 800x600 - 1024x768 - 1152x864 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1400x1050 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2560x1440 | | macOS | - 800x600 - 1024x768 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1366x768 - 1440x900 - 1600x900 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2048x1536 | | ### Geolocation Testing We provide an option where you can specify from which country you'd like to run the test from. Once you specify this option, the virtual machine we provision for your test will be configured to use a proxy in the country you specified. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', geoCountryCode: 'US' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) We currently support the following country codes: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States ### Upload This option allows you to upload a file to the test VM running the Playwright test. TestingBot will first download the file from the URL you specified and save it on the test VM so your test can use the file. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', upload: 'https://testingbot.com/assets/logo-head.png', uploadFilepath: '/tmp/test.log' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const page = await browser.newPage() await page.goto('http://localhost:3000') await page.locator('input[name="file-upload"]').click() await page.locator('input[name="file-upload"]').setInputFiles('/tmp/test.png') await page.click('upload-button') await browser.close() You need to specify both the download URL as `upload` and use `uploadFilepath` to indicate where TestingBot needs to put the file. We recommend using these directories to save your files: For Windows (`C:\test\`), for Linux/macOS: (`/tmp/`). ### Change Playwright Version By default, TestingBot will use the same Playwright version as the one that is running your test. If for some reason you need to specify a different version, you can use the `playwrightVersion` option. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, 'playwright:options': { playwrightVersion: '1.54.1' }, browserName: 'chrome', browserVersion: 'latest', name: 'First Test' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) ### Change Test Name Add a name to this test, which will show up in our member area and API. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', name: 'First Test' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || string | unnamed test | ### Group Tests A key you can use to group certain tests in the same build (for example in Jenkins). The builds will appear in our member area. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', build: 'First Build' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string | ### Timeout Control the timeout setting of the session. This setting, specified in seconds, controls when a session times out. A timeout occurs when a session has not received any commands from your Playwright test for the xx amount of seconds specified. If a certain Playwright command takes longer than the specified setting, the session will automatically close. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET, timeout: 90 }, browserName: 'chrome', browserVersion: 'latest' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || int (specify number of seconds) | 90 seconds | ### Maximum Test Duration The maximum duration for a single test. This is a safeguard to prevent bad tests from using up your credits. We generally recommend to keep tests short (less than 10 minutes). It's better to split up large tests in smaller individual tests. This keeps your tests fast and allows for more parallelization of your tests. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', maxduration: 1800 } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type | Default Value || int (specify number of seconds) | 1800 seconds (30 minutes) | ### Custom Metadata Send along custom data, for example your release, server, commit hash, ... This will show up on the test detail page in the TestingBot member area. const pw = require('playwright-core') const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', extra: 'Extra Information' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) Value Type || string | ### Startup Flags You can customize the startup flags of the browser by passing in extra flags. This is identical to passing `args` with Playwright. const pw = require('playwright-core') const startupFlags = [] startupFlags.push('--window-size=1280,720') startupFlags.push('--hide-scrollbars') const browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com` + `/playwright?key=api_key&secret=api_secret&browserName=chrome&startupFlags=${JSON.stringify(startupFlags)}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await browser.close() ### TestingBot Tunnel You can specify the `tunnelIdentifier` to [use Playwright with TestingBot Tunnel](https://testingbot.com/support/web-automate/playwright#tunnel). const pw = require('playwright-core') (async () => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest', tunnelIdentifier: 'myPlaywrightTunnel' } const browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) const context = await browser.newContext() const page = await context.newPage() await page.goto('http://localhost:3000/') await page.screenshot({ path: 'screenshot.png' }) await browser.close() })() By default we support proxying these ports for localhost testing: `[443, 80, 8080, 3030, 3000, 3001, 3400]`. If you need additional ports, please pass an array of port numbers to either `localHttpPorts` or `localHttpsPorts` ### Firefox Preferences You can pass in the [firefoxPreferences](https://playwright.dev/docs/api/class-browsertype#browser-type-launch-option-firefox-user-prefs) which Playwright accepts. const pw = require('playwright-core') (async () => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, 'playwright:options': { firefoxPreferences: '' }, browserName: 'firefox', browserVersion: 'latest' } await pw.firefox.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) })() ### Devtools You can pass in the [devTools](https://playwright.dev/docs/api/class-browsertype#browser-type-launch-option-devtools) which Playwright accepts. This is a Chromium-only option which decides whether to auto-open a Developer Tools panel for each tab during the test. const pw = require('playwright-core') (async () => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, 'playwright:options': { devtools: true }, browserName: 'chrome', browserVersion: 'latest' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) })() ### Patchright Patchright is a modified version of Playwright that tries to avoid detection by anti-bot systems. It patches several leaks, which are used by anti-scraper systems to detect Playwright automation. You can use Patchright with TestingBot, by passing in the `patchRightVersion` option, specifying the version of Patchright you want to use. const pw = require('playwright-core') (async () => { const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, 'playwright:options': { patchRightVersion: '1.52.5' }, browserName: 'chrome', browserVersion: 'latest' } await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) })() Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/recorder # Playwright Recorder Playwright offers a feature where you can record the actions in your browser to a Playwright script file. This allows you to easily create tests by recording your own actions, similar to [Selenium IDE](https://testingbot.com/support/web-automate/codeless-automation/add-test). To get started, install these packages: npm install playwright ## Example Now you can record your actions to a Playwright file: npx playwright codegen --target javascript -o example.js https://testingbot.com This command will start a Chromium browser and will record every action you take, in JavaScript format, to a file called `example.js`. You can choose to save the file in a different format, these are the options: - javascript - python - python-async - csharp The `example.js` file can contain something similar to this: const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: false }); const context = await browser.newContext(); // Open new page const page = await context.newPage(); // Go to https://testingbot.com/ await page.goto('https://testingbot.com/'); // Click text=Take your automated and manual testing to the next level. await page.click('text=Take your automated and manual testing to the next level.'); // Click img[alt="Automated Testing"] await page.click('img[alt="Automated Testing"]'); // Close page await page.close(); // --------------------- await context.close(); await browser.close(); })(); ## Run on TestingBot To run the generated file on a browser in the TestingBot grid, you'll have to modify the script. ### Before const browser = await chromium.launch(); ### After const capabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET }, browserName: 'chrome', browserVersion: 'latest' } const browser = await chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` }) ## Playwright Agents An alternative approach to recording tests would be to generate tests from your existing code. Playwright comes with [3 agents](https://playwright.dev/docs/test-agents) that can be used to create tests. - **planner** explores the app and produces a Markdown test plan - **generator** transforms the Markdown plan into the Playwright Test files - **healer** executes the test suite and automatically repairs failing tests, for example due to bad/missing locators To get started, use this command to initialize the agent definitions: npx playwright init-agents --loop=claude You can now use your AI tool of choice to generate tests and point these to use a remote TestingBot browser by replacing the `launch` command with a `connect` command, as shown in the previous sections. For example with a prompt: "Create one or more Playwright tests from the markdown test plan that was generated." Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/codeceptjs # CodeceptJS & Playwright CodeceptJS is an end-to-end testing framework which provides support for many automation drivers, including Playwright. To get started, please install these packages: npm install codeceptjs playwright --save To create a sample project from scratch, you can use this command: npx codeceptjs init ## Configure CodeceptJS with Playwright To configure CodeceptJS, please edit `codecept.conf.js` and make sure to add the `Playwright` helper. { // .. helpers: { Playwright: { url: "http://localhost", browser: 'chromium', chromium: { browserWSEndpoint: "wss://cloud.testingbot.com?key=YOUR_KEY&secret=YOUR_SECRET", cdpConnection: true } } } // .. } You can use the `browserWSEndpoint` URL to instruct CodeceptJS to use TestingBot's Playwright grid to run the tests on. ## Specifying browser and version To specify on which browser, browser version and platform your CodeceptJS + Playwright test should run, you can include both a `browserName` and `browserVersion` in the `browserWSEndpoint` URL. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Run your first CodeceptJS + Playwright test The example test below will open the TestingBot website and check to see if the word 'TestingBot' is included on the page. Feature('Test'); Scenario('test testingbot homepage', ({ I }) => { I.amOnPage('https://testingbot.com'); I.see('TestingBot'); }); Now you can run this first test on TestingBot. npx codeceptjs run --steps Test -- test something I am on page "https://testingbot.com" I see "TestingBot" ✔ OK in 1017ms OK | 1 passed // 10s This test will appear in your [Member Dashboard](https://testingbot.com/members). Test details will include a video of the test and any logs that were generated. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/playwright-parallel-testing # Parallel Testing **Parallel testing** lets you execute multiple Playwright tests at the same time, dramatically reducing your overall test suite duration and accelerating feedback cycles. On TestingBot's browser grid, you can easily run Playwright tests concurrently across more than 100 browser and device combinations. This enables you to validate your web application in multiple environments, all in parallel. The guide below will walk you through setting up and running Playwright tests concurrently using TestingBot’s scalable infrastructure. ## Parallel Example In the example below, we'll start various Playwright sessions on different browser versions, in the TestingBot cloud. const pw = require('playwright-core'); const doConnect = async (cap) => { cap['tb:options'] = { key: process.env.TB_KEY, secret: process.env.TB_SECRET } const browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(cap))}`, }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: `screenshot-${cap.browserName}-${cap.browserVersion}.png` }); await browser.close(); } const capabilities = [ { 'browserName': 'chrome', 'browserVersion': 'latest', 'platform': 'WIN10', }, { 'browserName': 'chrome', 'browserVersion': 'latest-1', 'platform': 'LINUX', }, { 'browserName': 'edge', 'browserVersion': 'latest', 'platform': 'SEQUOIA', }] (async () => { await Promise.all( capabilities.map((cap) => doConnect(cap)) ) console.log('All tests finished!'); })(); You can use `latest` and `latest-x` to automatically run on the latest browser version. ### Queueing Depending on your account subscription, you can run multiple tests in parallel. If you exceed your maximum allocated slots, the connection will be queued until a slot frees up. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/browsers # Browser and OS versions available for Playwright testing The TestingBot browser grid consists of +100 browser and OS combinations compatible with Playwright testing. We currently support these browser vendors with Playwright testing: - Chrome - Microsoft Edge - Firefox - Safari (WebKit) ## Specifying browser combination To indicate on which browser you want your Playwright test to run, please use the following parameters as a `browserWSEndpoint` value. - `browserName` - `browserVersion` - `platform` Capability | Description | Possible Values: || `browserName` | The name of the browser | `chrome`, `firefox`, `edge` and `webkit` (for Safari) | | `browserVersion` | The version of the browser | - **Chrome:** 72 and above - **Edge:** 80 and above - **Firefox:** 110 and above - **Safari:** will use the latest WebKit version bundled with Playwright You can use `latest`, `latest-1`, `latest-{x}` to test on the latest versions of the browser. | | `platform` | The Operating System where the test will run | - **Windows:** `WIN11`, `WIN10` - **macOS:** `CATALINA`, `BIGSUR`, `VENTURA`, `SONOMA`, `SEQUOIA`, `TAHOE` - `LINUX` | There was no release for version `82` of Chrome and Edge, so please do not specify this version. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/change-screen-resolution # Change desktop screen resolution with Playwright The TestingBot Desktop VMs (Windows, macOS and Linux) all support changing the screen-resolution before a test starts. We currently support the following screen resolutions: Value Type | Default Value | || string | "1280x1024" | Platform | Resolutions || Windows/Linux | - 800x600 - 1024x768 - 1152x864 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1400x1050 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2560x1440 | | macOS | - 800x600 - 1024x768 - 1280x768 - 1280x800 - 1280x960 - 1280x1024 - 1366x768 - 1440x900 - 1600x900 - 1600x1200 - 1680x1050 - 1920x1080 - 1920x1200 - 2048x1536 | | To change the screen resolution, please specify the `screen-resolution` parameter in the `browserWSEndpoint` URL. const pw = require('playwright-core'); (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&screen-resolution=1600x900', }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://testingbot.com/'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })(); Changing the screen resolution does not resize the viewport. To change the viewport with Playwright, please use `page.setViewportSize`. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/change-browser-options # Browser Options This document will guide you in specifying custom browser options, which can be used with Playwright testing. You can change the browser start arguments for a Chromium-based browser, or pass user-preferences for the Firefox browser. ## Set args for Chromium browsers In the example below we'll set custom browser `args` which will be used by the browser upon startup. const startupFlags = [] startupFlags.push('--window-size=1280,720') startupFlags.push('--hide-scrollbars') const browser = await pw.chromium.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright` + `?key=api_key&secret=api_secret&browserName=chrome&startupFlags=${JSON.stringify(startupFlags)}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await browser.close() You can use any of the [Chromium commandline switches](https://peter.sh/experiments/chromium-command-line-switches/). ## Set Firefox user preferences If you are running a Playwright test on Firefox, you can set the Firefox User Preferences. const firefoxPrefs = { 'browser.autoFocus': true } const browser = await pw.firefox.connect({ wsEndpoint: `wss://cloud.testingbot.com/playwright` + `?key=api_key&secret=api_secret&browserName=firefox&firefoxUserPrefs=${JSON.stringify(firefoxPrefs)}` }) const page = await browser.newPage() await page.goto('https://testingbot.com') await browser.close() For more information, please see [Firefox Preferences](https://support.mozilla.org/en-US/kb/about-config-editor-firefox). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/get-session-details # Get Playwright Session Details When a Playwright test runs on TestingBot, it will generate various artifacts such as logs, video, screenshots and other files. TestingBot will save these files for later retrieval, through our member dashboard or our [REST API](https://testingbot.com/support/api). To fetch these details through our REST API, you will need to know the unique identifier for each test. TestingBot provides a `testingbot_executor` which you can use to retrieve the `sessionId`, to use in your REST API calls. ## Fetch the sessionId To fetch the sessionId in your Playwright script, you can fetch the `sessionId` from the `getSessionDetails` method. See the example below, where we run a Playwright script, fetch the `getSessionDetails` at the end and update the test status via the TestingBot REST API. const TestingBot = require('testingbot-api'); const tb = new TestingBot({ api_key: 'api_key', api_secret: 'api_secret' }) const playwright = require('playwright-core'); (async () => { const browser = await playwright.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&platform=WIN10' }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com') const testingBotResponse = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'getSessionDetails'})}`) const sessionId = testingBotResponse.sessionId const testData = { "test[success]" : "1", "test[status_message]" : "test" }; await new Promise((resolve) => tb.updateTest(testData, sessionId, function(error, testDetails) { resolve(testDetails) })) await browser.close() })() Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/test-results # Test Results After running a Playwright test on TestingBot, you can see the test result in the [TestingBot Dashboard](https://testingbot.com#dashboard) overview. You can click each test to see a [detailed overview](https://testingbot.com#single) for each specific test. By default, a Playwright test runs in headless mode, so no video will be available. You can change this by [enabling video recording](https://testingbot.com/support/web-automate/playwright/options#screenrecorder). ## The Playwright Dashboard The dashboard contains an overview of all your previous test runs, together with some meta-data: - **Test Name** : you can pass this name via our [REST API](https://testingbot.com/support/web-automate/playwright#update). - **Pass/Failure state** : you can [indicate](https://testingbot.com/support/web-automate/playwright#update) whether this test passed or failed. - **Browser/Device** : the browser or device that was used by the test. TestingBot provides [more than 100 different browser/OS combinations](https://testingbot.com/support/web-automate/playwright/browsers). - **Start Date** : when we received the call to start your test. - **Test Duration** : how long it took for your test to run. This is the actual run time, potential queueing time is not included. ## Single Playwright Test Detail Page For each test, we have a test detail page, which shows an overview of all the data we have: - Test Name - [session details](https://testingbot.com/support/web-automate/playwright/get-session-details) of the test - the pass/failure state, if you used our [REST API](https://testingbot.com/support/web-automate/playwright#update) - the browser/device that was used by the test - the date when the test started - how long the test took to run - logs for the test - a video recording of the test (if the test ran with [recording enabled](https://testingbot.com/support/web-automate/playwright/options#screenrecorder)) - the user who started the test in your team ## Viewing results without the dashboard You can [share, embed and link to builds or individual tests](https://testingbot.com/support/other/sharing) without having to visit the dashboard. This is useful when you want to create your own reporting. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/debug-tests # Debug Failing Playwright Tests This document will guide you in using various techniques to debug Playwright tests running on TestingBot. We provide several features which can help you in locating problems or debugging Playwright tests. ## Interactive Session Our interactive session feature allows you to pause a running Playwright script, and inspect the remote browser with the included Developer Tools. Simply click the **Pause Test** button on the test page while the test is running and you will be navigated to a remote browser. You can now use your mouse and keyboard to interact with the browser and debug potential issues. One important thing to remember is that you will need to add a sleep/wait in your code, so that your Playwright commands stop being sent when debugging. ## Video Recording Every Playwright test that runs on TestingBot comes with a [recorded video](https://testingbot.com/support/web-automate/playwright/options#screenrecorder) of the entire screen, providing you run the Playwright test in `headful` mode. The video is available in our member area, where you can click each Playwright test. Or you can [fetch the video](https://testingbot.com/support/web-automate/playwright/get-session-details), together with other details, through our REST API. ## Log Files For every Playwright test running on TestingBot, we collect the browser's log. This log can be useful for pinpointing certain issues with your Playwright script. Log files are available in our member area, where you can click each Playwright test. Or you can [fetch the logs](https://testingbot.com/support/web-automate/playwright/get-session-details), together with other details, through our REST API. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/mark-test-status # Mark test status with Playwright The Playwright tests you run on TestingBot are using the `WebSocket` protocol to send commands to a remote browser. These commands instruct the remote browser what to do: click, type, resize, ... Because the logic of your test cases is inside your test script, TestingBot has no way of knowing if a test failed or passed. There is a way to send back the test status to TestingBot, by including a code snippet at the end of your test, where you know whether the test passed or failed. Below we'll go over two methods to send back the test status to TestingBot, so that we can show the pass/failure state in the dashboard and in the [TestingBot analytics](https://testingbot.com/support/analytics/guide). ## Mark test status from within a test script TestingBot has created a custom Playwright command which you can use in your Playwright scripts. You can pass in a `boolean` to indicate whether the test **passed** or **failed**. await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: { passed: false, reason: 'Title did not match' }})}`) This command will set the test as failed, with a specific reason which will be visible on the TestingBot test detail page. You can pass in the reason for a failure with the `reason` field. This command will return a JSON object with the `sessionId` of the test, which can be used with our [REST-API](https://testingbot.com/support/api). You would typically call this at the end of each test, where you know if the test failed or passed. For example, see the code snippet below where we use Chai's `expect` to verify if the test passed or not. const pw = require('playwright-core') const expect = require('chai').expect (async () => { const browser = await pw.chromium.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest', }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://testingbot.com/') const title = await page.title() try { expect(title).to.equal("Cross Browser Testing and Mobile App Testing. Test on web browsers, mobile emulators, simulators and physical mobile devices.", 'Expected page title is incorrect!') // This is ok, so mark the test as passed await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: true, reason: 'Title matched'}})}`) } catch { // Test failed, mark the test as failed on TestingBot await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: false, reason: 'Title did not match'}})}`) } await browser.close() })() ## Mark test status with API You can fetch the `sessionId` during an active Playwright test. This unique id can be used during or after the test to set the pass/fail state for the test. Marking the test as passed or failed will show the success state in the TestingBot test dashboard, on the individual test detail page and in the [TestingBot analytics](https://testingbot.com/support/analytics/guide) pages. To fetch the `sessionId`, please use the sample code below. const testingBotResponse = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'getSessionDetails'})}`) The `testingBotResponse` variable will contain a `sessionId` property which you can use: { "sessionId": "......" } With the `sessionId`, you can now mark the test as passed or failed via the [TestingBot REST-API](https://testingbot.com/support/api): $ curl "https://api.testingbot.com/v1/tests/:sessionId" \ -X PUT \ -d "test[success]=1" \ -u key:secret Learn more about this API call and other API calls on the TestingBot [API documentation](https://testingbot.com/support/api). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/browser-extension-testing # Testing Browser Extensions with Playwright Testing browser extensions on Chrome, Edge and Firefox is possible with the combination of Playwright and TestingBot. Please see the information below on how to load the extension before your test starts and how to perform UI testing with Playwright against these extensions. Currently these types of extensions are supported: Browser | Supported Format(s) | Example || [Chrome](https://testingbot.com#chrome) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) - `.crx` file | - `https://.../extension.zip` - `tb://sample-extension` | | [Firefox](https://testingbot.com#firefox) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, `lib/ directory`, ...) - `.xpi` file | - `https://.../extension.zip` - `tb://sample-extension` | | [Edge](https://testingbot.com#edge) | - `.zip` file, containing the extension source code (`manifest.json`, `src/ directory`, ...) - `.crx` file | - `https://.../extension.zip` - `tb://sample-extension` | ## TestingBot Storage With [TestingBot Storage](https://testingbot.com/support/api#upload), you can upload your extensions to the TestingBot servers. The advantage of this is that our test VMs can immediately download your extension from the TestingBot network, which is much faster than downloading from the public internet. The API call will return a unique identifier, similar to `tb://efe932jfk`. You can then use this identifier with the capability: `"load-extension" : "tb://..."` ## Chrome Browser Extension Testing with Playwright You can test your `.crx` extension by [uploading the extension](https://testingbot.com#storage) and using the URL of the extension with a `load-extension` capability. Because of Playwright limitations, we will need to use CDP to connect to Chrome based browsers in order to load extensions. const pw = require('playwright-core') (async () => { const browser = await pw.chromium.connectOverCDP('wss://cloud.testingbot.com/?key=api_key&secret=api_secret&browserName=chrome&browserVersion=latest&load-extension=tb://path-to-extension') const defaultContext = browser.contexts()[0] const page = defaultContext.pages()[0] await page.goto('https://www.google.com') // test if your extension does something await browser.close() })(); ### UI Testing Chrome Extensions You can test the UI and functionality of your extension in a remote Chrome browser. const pw = require('playwright-core') (async () => { const tbCapabilities = { browserName: 'chrome', platform: 'LINUX', key: process.env.TB_KEY, secret: process.env.TB_SECRET, 'load-extension': 'tb://path-to-extension' } const wsEndpoint = `wss://cloud.testingbot.com/?capabilities=${encodeURIComponent( JSON.stringify(tbCapabilities) )}`; const browser = await pw.chromium.connectOverCDP(wsEndpoint) const defaultContext = browser.contexts()[0] const page = defaultContext.pages()[0] await page.goto('chrome-extension://lliapakmekmldfaphofjcnbccemlgeoa/src/pages/popup/index.html') await browser.close() })(); ## Firefox Browser Extension Testing with Playwright To test your `.xpi` extension, you can specify a public URL or a [TestingBot Storage](https://testingbot.com#storage) URL in the `load-extension` capability. const pw = require('playwright-core') (async () => { const browser = await pw.firefox.connect({ wsEndpoint: 'wss://cloud.testingbot.com/playwright?key=api_key&secret=api_secret&browserName=firefox&browserVersion=latest&load-extension=tb://path-to-extension' }) const context = await browser.newContext() const page = await context.newPage() await page.goto('https://www.google.com') // test if your extension does something await browser.close() })(); ### UI Testing Firefox Extensions You can test the UI and functionality of your extension in a remote Mozilla Firefox browser. If you want to test the UI of your Firefox extension, the `moz-extension://` URL, you will need to specify the extension ID in the URL. Because TestingBot installs the extension as a temporary extension, the id will always be different as it is generated as a random uuid(4). TestingBot provides a capability to hardcode your Firefox extension to a fixed uuid which you've generated, by using the `firefoxExtensionMap` capability. To use this, you could set the ID in the `manifest.json` of the extension: const pw = require('playwright-core') (async () => { const tbCapabilities = { browserName: 'firefox', platform: 'LINUX', key: process.env.TB_KEY, secret: process.env.TB_SECRET, 'load-extension': 'tb://path-to-extension', 'firefoxExtensionMap': { 'addon@testingbot.com': '3d9b1639-77fb-44a1-888a-6d97d773e96b' } } const wsEndpoint = `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent( JSON.stringify(tbCapabilities) )}`; const browser = await pw.firefox.connect({ wsEndpoint }) const context = await browser.newContext() const page = await context.newPage() await page.goto('moz-extension://3d9b1639-77fb-44a1-888a-6d97d773e96b/src/pages/popup/index.html') await browser.close() })(); ## Edge Browser Extension Testing with Playwright You can test your Microsoft Edge extension by [uploading the extension](https://testingbot.com#storage) and using the URL of the extension with a `load-extension` capability. Because of Playwright limitations, we will need to use CDP to connect to Edge based browsers in order to load extensions. const pw = require('playwright-core') (async () => { const browser = await pw.chromium.connectOverCDP('wss://cloud.testingbot.com/?key=api_key&secret=api_secret&browserName=microsoftedge&browserVersion=latest&load-extension=tb://path-to-extension') const defaultContext = browser.contexts()[0] const page = defaultContext.pages()[0] await page.goto('https://www.google.com') // test if your extension does something await browser.close() })(); ### UI Testing Edge Extensions You can test the UI and functionality of your extension in a remote Edge browser. const pw = require('playwright-core') (async () => { const tbCapabilities = { browserName: 'edge', platform: 'WIN10', key: process.env.TB_KEY, secret: process.env.TB_SECRET, 'load-extension': 'tb://path-to-extension' } const wsEndpoint = `wss://cloud.testingbot.com/?capabilities=${encodeURIComponent( JSON.stringify(tbCapabilities) )}`; const browser = await pw.chromium.connectOverCDP(wsEndpoint) const defaultContext = browser.contexts()[0] const page = defaultContext.pages()[0] await page.goto('extension://lliapakmekmldfaphofjcnbccemlgeoa/src/pages/popup/index.html') await browser.close() })(); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/playwright/mobile # Mobile Playwright Testing Playwright offers [experimental support for Android automation](https://playwright.dev/docs/api/class-android). TestingBot provides a grid of remote Android devices and emulators. You can use Playwright scripts to automate Chrome for Android browsers and Android WebViews. npm i playwright-core const { _android } = require('playwright-core'); (async () => { const tbCapabilities = { browserName: 'chrome', platformName: 'Android', deviceName: 'Pixel 8', browserVersion: '14.0', key: process.env.TB_KEY, secret: process.env.TB_SECRET } const wsEndpoint = `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(tbCapabilities))}` const device = await _android.connect(wsEndpoint) const context = await device.launchBrowser() const [page] = context.pages() await page.goto('https://testingbot.com') const resp = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'setSessionStatus',arguments: {passed: true }})}`); await page.close() await context.close() await device.close() })(); The example above will connect to a remote Pixel 8 device running Android 14. It will open the Chrome browser and navigate to TestingBot's homepage. After running this test, a video together with logs will be available in the TestingBot member area. ## Specify Android Device You can specify a specific Android device with the `deviceName` and `version` capabilities. These capabilities can target either Android emulators, or physical Android devices. ![Android OS selected](https://testingbot.com/assets/environments/svg/android-1b3d235e17522e2238e1c55b4e9cdd41219f653cd958ea065877d3813f32ffc3.svg)Android 16.0›Pixel 9 Loading environments... Please wait while we load the available browsers and platforms. We offer special parameters which you can use to allocate a device: Regex Input | Result || `"Pixel.*"` | This will allocate any available Pixel device (phone) | | `"*"` | This will allocate a random available Android device | | `"Samsung [20-21]"` | This will allocate either a Samsung 20 or 21 | Some Examples: // find any Samsung Galaxy, except 23 const tbCapabilities = { browserName: 'chrome', platformName: 'Android', deviceName: '^(Galaxy.*)(?!23)$', } // find any device which name starts with Pixel const tbCapabilities = { browserName: 'chrome', platformName: 'Android', deviceName: 'Pixel.*', } ## Testing WebViews Playwright can connect and automate Android WebViews. Please see the example below, where we use `device.webView({ pkg: 'org.chromium.webview_shell' })`. const { _android } = require('playwright-core'); (async () => { const tbCapabilities = { browserName: 'chrome', platformName: 'Android', deviceName: 'Pixel 8', browserVersion: '14.0', key: process.env.TB_KEY, secret: process.env.TB_SECRET } const wsEndpoint = `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(tbCapabilities))}` const device = await _android.connect(wsEndpoint) const context = await device.launchBrowser() // Launch an application with WebView. await device.shell('am force-stop org.chromium.webview_shell'); await device.shell('am start org.chromium.webview_shell/.WebViewBrowserActivity'); // Get the WebView. const webview = await device.webView({ pkg: 'org.chromium.webview_shell' }); // Fill the URL box. await device.fill({ res: 'org.chromium.webview_shell:id/url_field', }, 'testingbot.com'); await device.press({ res: 'org.chromium.webview_shell:id/url_field', }, 'Enter'); const page = await webview.page(); await page.waitForNavigation({ url: /.*testingbot.*/ }); console.log(await page.title()); await page.close() await context.close() await device.close() })(); ## Playwright Emulation Playwright allows you to emulate specific devices, such as mobile phones or tablets. This is similar in functionality to other Devtools, where the viewport size is changed, together with the user-agent and other settings. You can specify your own custom device configurations, where you can [override the viewport size](https://playwright.dev/docs/emulation#viewport). Create a file called `playwright.config.js` with the following contents: import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 720 } } }, { name: 'Mobile Safari', use: { ...devices['iPhone 15'] } } ] }); You will also need to create a `testingbot.config.js` file, which will contain code to connect to the TestingBot Playwright server: export function getConnectWsEndpoint(userCapabilities) { const defaultCapabilities = { 'tb:options': { key: process.env.TB_KEY, secret: process.env.TB_SECRET } } const capabilities = { ...defaultCapabilities, ...userCapabilities } const connectUrl = `wss://cloud.testingbot.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}` return connectUrl } You can now include a [sample Playwright test](https://testingbot.com/support/web-automate/playwright/playwright-test#example) and run it on the TestingBot cloud. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress # Cypress Testing Cypress provides easy and fast testing on Chrome, Firefox and Microsoft Edge. TestingBot has a CLI tool that will run your Cypress tests on the TestingBot browser grid. Perform Cypress automation in the cloud, with TestingBot's browser grid. This will allow you to run Cypress tests in parallel on a wide collection of browsers; test on different versions and operating systems. By default the CLI is using **Cypress v13.3.3** ([change](https://testingbot.com/support/web-automate/cypress/version)). Testing is available on these platforms: key | value | possible values || platform | The Operating System (OS) you want to run the tests on. | - `WIN11` - `WIN10` - `TAHOE` - `SEQUOIA` - `SONOMA` - `VENTURA` - `MONTEREY` - `BIGSUR` - `CATALINA` - `MOJAVE` | | browserName | The browser you want to run the tests on. | `chrome`, `firefox` and `microsoftedge` | | version | The version of the browser | **Chrome:** version `70` to `latest` **Firefox:** version `70` to `latest` **Edge:** version `80` to `latest` **(WIN10 only)** | | screenResolution | Specify a screen resolution for your test. | See a [list of screen resolutions](https://testingbot.com/support/web-automate/selenium/test-options#screenresolution) | ## Install the CLI To get started with the CLI, please install it with `npm` or `yarn`: $ npm install testingbot-cypress-cli You can find the repository for the CLI on [github@testingbot-cypress-cli](https://github.com/testingbot/testingbot-cypress-cli) ## Configuration Once installed, you'll need to provide the CLI with a `testingbot.json` configuration file. This file contains various settings, including the path to your Cypress tests. To generate a configuration file, you can use the `init` command: $ testingbot-cypress init Please add the `key` and `secret` you obtained from the TestingBot [member dashboard](https://testingbot.com/members/user/edit) in the `testingbot.json` file. Next, please supply `cypress_proj_dir` with the path to the folder that contains the `cypress.json` or `cypress.config.js` file. As an example, you can use the [Cypress Kitchen Sink Example](https://github.com/cypress-io/cypress-example-kitchensink). Before you can run your tests, you need to specify on which browser (version) and platform you'd like to test. You can specify the browsers you want to use in the `testingbot.json` file: { "auth": { "key": "TESTINGBOT_KEY", "secret": "TESTINGBOT_SECRET" }, "browsers": [ { "browserName": "chrome", "platform": "VENTURA", "version": "latest" }, { "browserName": "chrome", "platform": "WIN10", "version": "latest" } ], "run_settings": { "cypress_project_dir": ".../cypress/cypress-example-kitchensink", "build_name": "cypress-build", "npm_dependencies": {}, "package_config_options": {}, "start_tunnel": true, "local_ports": [8080], "realTimeLogs": true, "parallel": 5 }, "tunnel_settings": { "verbose": false } } ## Run tests You are now ready to run your Cypress tests on TestingBot. Instead of using the Cypress test runner, you can use TestingBot's test runner. Run the following command: $ testingbot-cypress run This will zip your Cypress tests, upload them to TestingBot and instruct TestingBot to start running the tests on the platform(s) you specified in the configuration file. The CLI will then display a link to view a live feed of your Cypress tests and will return realtime logs of the Cypress client running on TestingBot. Once the tests have finished running, the CLI will exit with `code 1` (failure) or `code 0` (success). ## Example As an example, you can use [cypress-example-kitchensink](https://github.com/cypress-io/cypress-example-kitchensink) These are the steps you need to follow to run the example on TestingBot: - Clone the kitchensink repo and install the dependencies: `npm install` - Start the kitchensink example: `npm start` - Add the local port used by kitchensink (8080) to the `local_ports` array, this way the TestingBot VMs can access the port. - Change the `cypress_project_dir` to point to the path where you installed the example. - Run the tests: $ testingbot-cypress run - Test results will appear in your console and on the [TestingBot dashboard](https://testingbot.com/members). ## Options Several options are available in the `testingbot.json` file. - `cypress_project_dir`: this needs to be specified and is the directory (absolute path) where your cypress configuration file is located. `cypress.json` or `cypress.config.js`. - `build_name`: this will set the build name on TestingBot. All Cypress tests will be grouped under this name. - `npm_dependencies`: you can list the NPM dependencies that your Cypress project requires here: "npm_dependencies": { "npm-package-1": "^1.0.1", "npm-package-2": "^1.2.3-beta", } - `package_config_options`: the config options for each of the npm dependencies you specified: "package_config_options": { "npm-package-1": { "option1": true, "option2": "some-value" } } - `start_tunnel`: should the CLI start a [TestingBot Tunnel](https://testingbot.com/support/tunnel) to access websites on your local computer/network? - `local_ports`: an array of ports that Cypress is using on your local computer. Use this in combination with `start_tunnel = true` to run tests from your local computer or network. - `realTimeLogs`: should the CLI display a real-time feed of the Cypress logs? - `tunnel_settings`: add additional [Tunnel options](https://testingbot.com/support/tunnel/commandline) to the TestingBot tunnel process. ## Environment Variables The CLI supports various Environment Variables: - You can use `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` to pass the TestingBot credentials to the CLI. - If you set `TESTINGBOT_CI=1` then the CLI will output the `TestingBotSessionID` which can be used in combination with one of our [CI plugins](https://testingbot.com/integrations#ci). ## Limitations While TestingBot supports most of the features Cypress provides, there are some that are not yet supported. Below is a list of features we currently do not support. If you'd like us to add support for these, please [reach out](https://testingbot.com/contact/new). - Cypress Component Testing - Module API - Test Replay Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/authentication # Authentication Options To use the TestingBot CLI, you'll need to authenticate with our Service. You can authenticate in two ways: - Specify [environment variables](https://testingbot.com#environment) - [Adding the credentials](https://testingbot.com#file) in the `testingbot.json` file ## Environment Variables You can set the following two environment variables before using the CLI: TESTINGBOT_KEY=your_testingbot_key TESTINGBOT_SECRET=your_testingbot_secret The CLI will automatically pick up these two variables and use them to authenticate. You can find these two values in our [member dashboard](https://testingbot.com/members/user/edit). ## Credentials in Config File You can set the [TestingBot Key and Secret values](https://testingbot.com/members/user/edit) in the `testingbot.json` file: { "auth": { "key": "TESTINGBOT_KEY", "secret": "TESTINGBOT_SECRET" }, ... } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/reporting # Reporting The TestingBot Cypress CLI contains an option to generate reports from your Cypress Runs, similar to other reporters such as mocha-awesome. To generate a report, please specify the `--reporter` flag: Argument | Shorthand Argument | Accepted Values || `--reporter` | `-r` | You can choose to use the `json` reporter, or the `junit` reporter | ## JUnit Reporter The JUnit reporter is especially useful if you intend to run your Cypress tests in a CI such as Jenkins. Here's an example of how to generate a JUnit report: testingbot-cypress run --reporter junit Most CI systems will be able to parse the report. The CI can then show a list of specs/tests that you ran on TestingBot, together with information such as: - How long each spec took to run - Whether the spec passed or not - The full error message if a spec failed By default, the reporter will output the report in a file called `test-results.xml`, in the same directory where you run the CLI command from. You can choose to change the location of this file with: testingbot-cypress run --reporter junit --reporter-options mochaFile=/home/user/reports/my-report.xml ## JSON Reporter The JSON reporter will output all data to a JSON file, similar to a report generated with [mochawesome-report-generator](https://github.com/adamgruber/mochawesome-report-generator) Here's an example of how to generate a JSON report: testingbot-cypress run --reporter json By default, the reporter will output the report in a file called `results.json`, in the same directory where you run the CLI command from. You can choose to change the location of this file with: testingbot-cypress run --reporter json --reporter-options mochaFile=/home/user/reports/my-report.json Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/variables # Cypress Test Environment Variables You can easily setup test environment variables to be used with Cypress and TestingBot Cypress CLI. There are currently three ways to do this: 1. Using the `env` option key in your Cypress configuration file 2. Create a `cypress.env.json` file and specify your environment variables 3. Use the `--env` CLI flag with `testingbot-cypress` ## Cypress Configuration File Cypress allows you to specify your environment variables in the Cypress config file (`cypress.json` or `cypress.config.js`), under the `env` option key. You can learn more about this option in the [Cypress Documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Option-1-configuration-file). "env": { "signup_url": "/signup", "pricing_url": "/pricing" } You can then access these values in Cypress with: Cypress.env() // {signup_url: '/signup', pricing_url: '/pricing'} Cypress.env('signup_url') // '/signup' Cypress.env('pricing_url') // '/pricing' ## cypress.env.json You can also create your own `cypress.env.json` file. TestingBot's Cypress CLI will send this together with your specs to instruct Cypress to use these environment variables. Values in this file will overwrite conflicting environment variables in your Cypress configuration file. See the [Cypress env.json documentation](https://docs.cypress.io/guides/guides/environment-variables.html#Option-2-cypress-env-json). { "host": "testingbot.com", "api": "api.testingbot.com" } You can then access these values in Cypress with: Cypress.env() // {host: 'testingbot.com', api: 'api.testingbot.com'} Cypress.env('host') // 'testingbot.com' Cypress.env('api') // 'api.testingbot.com' ## CLI Flag You can also pass a comma-separated list of environment variables with the TestingBot Cypress CLI. We will pass these values to the [Cypress Runner](https://docs.cypress.io/guides/guides/environment-variables.html#Option-4-env). Argument | Shorthand Argument | Possible values || `--env` | `-e` | comma-separated environment variables | testingbot-cypress run --env host=testingbot.com,api=api.testingbot.com You can then access these values in Cypress with: Cypress.env() // {host: 'testingbot.com', api: 'api.testingbot.com'} Cypress.env('host') // 'testingbot.com' Cypress.env('api') // 'api.testingbot.com' Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/capabilities # Browsers & Platforms TestingBot allows you to run your Cypress tests on hundreds of browser & platform combinations. You can use the `browsers` field in the `testingbot.json` file to indicate on which browsers & platforms you want to run your Cypress tests: key | value | possible values || platform | The Operating System (OS) you want to run the tests on. | `WIN11`, `WIN10`, `TAHOE`, `SEQUOIA`, `VENTURA` and `MONTEREY` | | browserName | The browser you want to run the tests on. | `chrome`, `firefox` and `microsoftedge` | | version | The version of the browser | **Chrome:** version `70` to `latest` **Firefox:** version `70` to `latest` **Edge:** version `80` to `latest` **(WIN10 only)** | ## Example Configuration Please see the example below on how to specify multiple browsers: { ... "browsers": [ { "browserName": "chrome", "platform": "VENTURA", "version": "latest" }, { "browserName": "chrome", "platform": "WIN10", "version": "latest" }, { "browserName": "firefox", "platform": "MONTEREY", "version": "latest-1" } ], ... } You can use `latest` or `latest-X` to always test on the latest versions, or specify a specific browser version. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/reference # CLI Reference Below you can find an overview of all the various options that the TestingBot Cypress CLI provides. Command | Purpose || `init` | This will initialize a new `testingbot.json` file, which contains the default configuration necessary to run tests | | `run` | [Start running your tests](https://testingbot.com#run) | ## Start running your tests To run your Cypress tests, please use this command, together with any of the optional arguments: testingbot-cypress run Argument | Shorthand Argument | Accepted Values | Description || `--config-file` | `-cf` | The path to the `testingbot.json` config file. By default, this will look in the current directory for a `testingbot.json` file. | The `testingbot.json` config file is used to communicate with TestingBot. | | `--group` | | Accepts a `string`, can be any name. For example a build identifier from your CI. | Group all these tests in the TestingBot dashboard. Similar to our [build option](https://testingbot.com/support/web-automate/selenium/test-options#idletimeout). | | `--headless` | | Requires no arguments. If you pass this option, TestingBot will run the Cypress tests in headless mode. | With headless mode, tests will run without a UI and may run faster. | | `--parallel` | | Requires an integer, for example `--parallel 5` If you pass this option, TestingBot will split up your specs and run these on separate machines. | Depending on your plan, you can run your Cypress tests in parallel on TestingBot. This significantly cuts down the time it takes to run your full Cypress test suite. | | `--specs` | `-s` | Accepts a comma-separated list of files, or a glob. | Runs a subset of your specs. See [our Cypress Specs documentation](https://testingbot.com/support/web-automate/cypress/specs) for more information. | | `--env` | `-e` | Accepts a comma-separated list of environment variables | Sets the Cypress Environment Variables. See [our Cypress Environment Variables documentation](https://testingbot.com/support/web-automate/cypress/variables) for more information. | ## Stopping your tests While the TestingBot CLI is running your tests, you may decide that you want to stop the actively running tests. You can do this easily: - use `CTRL+C` in your terminal window - send a `SIGHUP` kill command to the CLI process Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/specs # Cypress Spec Files By default, Cypress will run all the spec files it can find. You can specify a `--specs` option with the TestingBot CLI to only run a subset of your specs on TestingBot. Argument | Shorthand Argument | Possible values || `--specs` | `-s` | comma-separated paths or globs for your spec files | testingbot-cypress run --specs "cypress/integration/examples/window.spec.js" testingbot-cypress run --specs "cypress/integration/register/**/*" testingbot-cypress run --specs "cypress/integration/examples/files.spec.js,cypress/integration/examples/navigation.spec.js" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/upload # Upload Options The TestingBot Cypress CLI will automatically collect and upload your Cypress tests and configuration files, to run these on the TestingBot Browser Grid. These files are uploaded to [TestingBot Storage](https://testingbot.com/support/api#upload), where they will only be used for running tests (in parallel) on TestingBot. However, you may want to exclude certain files from being uploaded, if: - The ZIP file is too large (over 150MB) - The upload is taking too long - You are zipping unnecessary files, for example `node_modules/*` If you're looking to only run a subset of tests, please see the [specs](https://testingbot.com/support/web-automate/cypress/specs) option. ## Exclude files with Run Settings To exclude certain files, please specify the file, directory, or a wildcard combination in the `run_settings` with `exclude`: { ... "run_settings": { ... "exclude": ["some-folder/test.js", "static/*.pdf"] ... } ... } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/tutorial # Cypress Tutorial This documentation page is a quick tutorial on how to set up an example app, with Cypress tests, and run Cypress Tests on multiple browsers in parallel on TestingBot. ## Install the Example The most popular example with Cypress is the [Cypress Kitchensink Example](https://github.com/cypress-io/cypress-example-kitchensink). You can [download](https://github.com/cypress-io/cypress-example-kitchensink/archive/master.zip) or clone it from GitHub: [Cypress v10 and higher](https://testingbot.com#)[Cypress v9 and lower](https://testingbot.com#) git clone https://github.com/cypress-io/cypress-example-kitchensink.git git clone https://github.com/cypress-io/cypress-example-kitchensink.git git checkout ab10094ef7b199ae7febafec413a0626414bcd3c Once you have the example on your computer, navigate to the directory and install its dependencies: cd cypress-example-kitchensink npm install ## Configuration Once you have the example on your computer, you can install the TestingBot Cypress CLI: npm install -g testingbot-cypress-cli Next, you'll need to create a `testingbot.json` file which will hold the configuration and authentication details to connect with TestingBot. You can quickly generate a new configuration with the CLI: testingbot-cypress init This will create the json file in the current directory. Now you can edit the file: - **auth** : add your TestingBot `Key` and `Secret` (obtained from [member dashboard](https://testingbot.com/members/user/edit)) in the auth code block - **browsers** : specify the browsers that you want to run your test on - **run\_settings** : various options that you can configure to customize the Cypress Tests - **tunnel\_settings** : options to customize the [TestingBot tunnel](https://testingbot.com/support/tunnel), usually you will not need to modify this This is a good example configuration to continue with the tutorial: { "auth": { "key": "TESTINGBOT_KEY", "secret": "TESTINGBOT_SECRET" }, "browsers": [ { "browserName": "chrome", "platform": "VENTURA", "version": "latest" } ], "run_settings": { "cypress_project_dir": ".../cypress/cypress-example-kitchensink", "build_name": "cypress-build", "npm_dependencies": {}, "package_config_options": {}, "start_tunnel": true, "local_ports": [8080], "realTimeLogs": true, "parallel": 2 }, "tunnel_settings": { "verbose": false } } ## Setup the Example Next, you'll need to start up the kitchen-sink webserver. Simply go to the directory of the example, and run this command: npm start By default this app uses `localhost:8080` for its web server. That's the reason why we added `8080` to the `local_ports` configuration above. It allows the CLI to access this webserver. ## Run the tests You can now run the tests: testingbot-cypress run The test results, together with a video and logs of the tests, will be available in the [TestingBot dashboard](https://testingbot.com/members). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/version # Specifying Cypress Version TestingBot has installed several versions of Cypress on its VMs. You can request the TestingBot Cypress CLI to test on a specific version by specifying `cypressVersion` in the `testingbot.json` file. { "run_settings": { "cypress_project_dir": "/path/to/directory-that-contains-cypress-config-file", "build_name": "build-name", "start_tunnel": true, "local_ports": [], "realTimeLogs": true, "cypressVersion": "13.3.3" } } Currently we support these versions of Cypress: - 14.2.0 - 13.17.0 - 13.3.3 (default) - 12.5.1 - 10.0.0 - 9.1.0 - 8.0.0 - 6.5.0 - 5.6.0 - 4.12.1 If you'd like to test on another version, please [let us know](https://testingbot.com/contact/new). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/devtools # Run Cypress tests recorded with Chrome DevTools Chrome allows you to record your actions and generate scripts, all through Chrome DevTools. **Recorder** is a feature that can record (and replay) actions you make during a browser session. Various export formats are supported by **Recorder** , including the ability to export as a Cypress test script. ## Requirements Before you can get started, make sure to follow these requirements: - You need to be using Chrome 89 or higher. Previous versions do not come with the **Recorder** feature. - Install the Chrome Extension [Cypress Chrome Recorder](https://chrome.google.com/webstore/detail/cypress-chrome-recorder/fellcphjglholofndfmmjmheedhomgin/related) - TestingBot's Cypress CLI is installed, through [npm install testingbot-cypress-cli](https://testingbot.com/support/web-automate/cypress#install). ## Record your actions in Chrome ### Enable Recorder in Chrome First, we'll need to enable the recorder in Chrome. Please follow these steps: 1. Open Chrome and click the **More options** icon, then select **Developer Tools** from the More Tools option. 2. Once you're in the Developer Tools, click the **More options** (a vertical ellipses icon) and select **Recorder** from the **More Tools** option. 3. A Recorder tab will appear, with a button **Create a new recording**. You are now ready to start recording. ### Record Actions in Chrome We can now start recording a user flow in Chrome. Proceed with the following steps to start recording. 1. In **Recorder** , click the **Start new recording** button. 2. Enter a name in the **RECORDING NAME** input field. 3. Click the **Start a new recording** button at the bottom of the panel. 4. Perform various actions in Chrome while the recorder is running. 5. When you are finished, click the **End recording** button. ### Export recorded Actions Click the **Export** icon and select the **Export as a Cypress Test script** option. Save the exported file to your local disk, in a file called **cdp-testingbot.cy.js** in a folder **cypress/e2e/**. It should contain code similar to the code below. describe("cdp-testingbot", () => { it("test with cdp on testingbot", () => { cy.viewport(1280, 824); cy.visit("https://testingbot.com/"); }); }); Next, create a file **cypress.config.js** with the following content: module.exports = { 'projectId': '4b7344', e2e: {}, } ## Run the recorded Cypress actions on TestingBot To start running the test on TestingBot, you first need to create a `testingbot.json` file. $ testingbot-cypress init Please add the `key` and `secret` you obtained from the TestingBot [member dashboard](https://testingbot.com/members/user/edit) in the `testingbot.json` file. Before you can run your tests, you need to specify on which browser (version) and platform you'd like to test. You can specify the browsers you want to use in the `testingbot.json` file: { "auth": { "key": "TESTINGBOT_KEY", "secret": "TESTINGBOT_SECRET" }, "browsers": [ { "browserName": "chrome", "platform": "WIN10", "version": "latest" } ], "run_settings": { "cypress_project_dir": "folder-here", "build_name": "cypress-recorded-actions", "npm_dependencies": {}, "package_config_options": {}, "realTimeLogs": true } } Make sure to change the **cypress\_project\_dir** to the folder that contains your **cypress.config.js** file. Next, you can start running the tests. $ testingbot-cypress run Test results will appear in your console and on the [TestingBot dashboard](https://testingbot.com/members). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/geolocation # Cypress Geolocation Testing TestingBot provides Cypress testing in the cloud. Together with TestingBot's IP GeoLocation feature, you are able to run Cypress tests from various countries around the world. The advantages of using geolocation testing with Cypress are that you can verify various scenarios in your tests, such as: - Test translated webpages - Verify localized pricing: different currencies - Test speed from various locations around the world We currently support the following geolocations for Cypress testing: - **'\*'** : this will take a random country from the list below - **'AU'** : Australia - **'BH'** : Bahrain - **'BE'** : Belgium - **'BR'** : Brazil - **'CA'** : Canada - **'CL'** : Chile - **'FR'** : France - **'DE'** : Germany - **'IN'** : India - **'IT'** : Italy - **'JP'** : Japan - **'NO'** : Norway - **'SG'** : Singapore - **'ZA'** : South Africa - **'SE'** : Sweden - **'CH'** : Switzerland - **'AE'** : United Arab Emirates - **'GB'** : United Kingdom - **'US'** : United States ## Code Example You can specify the ISO code of the geolocation in the `testingbot.json` file, as a capability: { ... "browsers": [ { "browserName": "chrome", "platform": "WIN10", "version": "latest", "testingbot.geoCountryCode": "DE" } ], ... } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/typescript # Cypress Typescript Testing TestingBot offers a service similar to Cypress Cloud, where you can run Cypress tests on multiple browsers in the cloud, simultaneously. On this page, we will focus on how to run a Cypress test, built with Typescript, on TestingBot's remote browser grid. ## Setup Typescript and Cypress TestingBot provides a ready-to-use Github example: [typescript-cypress-testingbot](https://github.com/testingbot/typescript-cypress-testingbot). To get started, create a new project and add the necessary dependencies: - `npm init` - `npm install testingbot-cypress-cli typescript cypress --save-dev` - Next, create a `tsconfig.json` file with the following contents: - Let's also create a `cypress.config.ts` file (notice the `.ts` indicating this is a Typescript project). ## Typescript Example Now that everything is set up, we can add a first test. Create a `cypress` directory, which will contain 2 more directories: - `e2e` - `support` ### e2e.cy.ts file The `e2e.cy.ts` file in the `cypress/e2e` directory contains our test logic: describe('TestingBot Demo test', () => { beforeEach(() => { cy.visit('https://testingbot.com') }) it('Verify title', () => { cy.title().should('include', 'TestingBot') }) }) ### e2e.ts file Another file, `e2e.ts`, needs to be added in the `cypress/support` directory, containing: // Import commands.js using ES2015 syntax: import './commands' `commands.ts` can be an empty file for now. ## Run the Cypress test There's one more thing left for us to do. We need to create a `testingbot.json` file, which needs to contain a couple of things for TestingBot to run your test. To create the file, execute the following command in the base directory of your project: testingbot-cypress init You can now edit the `testingbot.json` file. { "auth": { "key": "TESTINGBOT_KEY", "secret": "TESTINGBOT_SECRET" }, "browsers": [ { "browserName": "chrome", "platform": "VENTURA", "version": "latest" } ], "run_settings": { "cypress_project_dir": ".../cypress/cypress-example-kitchensink", "build_name": "cypress-build", "npm_dependencies": { "typescript": "^5.2.2" }, "package_config_options": {}, "start_tunnel": false, "realTimeLogs": true, "parallel": 1 }, "tunnel_settings": { "verbose": false } } Make sure to specify the same typescript dependency in `npm_dependencies` as the one in your `package.json`. This will instruct TestingBot to use the same Typescript version for running your tests. Finally, to run the test, you can run the following command: testingbot-cypress run The test results, together with a video and logs of the tests, will be available in the [TestingBot dashboard](https://testingbot.com/members). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/web-automate/cypress/timezone # Configure Timezone During Cypress testing, you might want to test behaviour specific to a certain timezone. TestingBot allows you to configure the timezone of the machines that run your Cypress tests. Please use a timezone format from the [list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). { ... "browsers": [ { "browserName": "chrome", "platform": "WIN10", "version": "latest", "timezone": "New_York" } ], ... } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing # Visual Testing with TestingBot Visual testing is a testing technique which aims to verify the visual aspects of a user interface (UI). If you want to make sure that no unintended visual mistakes occur, you will need to compare the visual appearance of your website or mobile app with a golden image (commonly known as baseline image). TestingBot makes it easy for you to run visual tests against the pages of your website, or the screens of your mobile app. You will be able to run visual tests across different browsers, OS versions and mobile devices. ## Getting started with UI Testing There are currently two options to use visual UI testing on TestingBot: 1. [Automated Visual Testing](https://testingbot.com/support/visual-testing/automated) Integrate TestingBot's UI comparison testing directly in your existing automated test scripts. 2. [Run scheduled visual tests](https://testingbot.com/support/visual-testing/codeless) Requires no code - simply specify URLs to your website and TestingBot will regularly inspect your website for UI changes. You'll receive an alert when a visual regression is detected. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/stabilize-screenshots # Stabilize Screenshots for Visual Testing During visual testing, we're comparing a screenshot with a previous screenshot. If a difference is detected, the visual test is considered a failed test. In order to avoid false positives during the comparison of two screenshots, it's important to make sure we prevent as much unwanted and unimportant dynamic data from the screenshot as possible. ## Freeze CSS Animations Right before TestingBot takes a screenshot, we will disable any CSS animations currently running on the page. TestingBot will freeze CSS `animation` and `transition` styles. Once the screenshot has been taken, the CSS animations will run just like before. ## Lazy Loaded Images Some images on the webpage might be marked as lazy loading images. If you are taking a full-page screenshot, TestingBot will force-load all images marked as lazy images, to make sure the entire page is visually tested. ## Mobile Statusbars When testing on (physical) mobile devices, a statusbar might be present on the screen, containing the current time. TestingBot will automatically remove the statusbar from the image, because otherwise the time indicator would trigger a visual difference compared to the baseline. ## Date/Time on webpages A webpage might display the current date or time. In order to avoid marking this as a difference, the date and time of the webpage is frozen to `2024-01-01T12:00:00Z`. Once the screenshot has been taken, the date and time is unfrozen. ## Native browser controls Right before TestingBot takes a screenshot, the caret and the scrollbar on the page will be hidden, in order to avoid false positives with focused text inputs. After the screenshot, these changes will be reverted. ## Visual Test Options TestingBot offers these features to stabilize your screenshots: ### Ignore Specific Regions You can ignore specific regions, defined in pixel coordinates, from the screenshot: ignoreRegions = [{ "x1": number, "y1": number, "x2": number, "y2": number }] ### Ignore Specific Selectors Pass an array of CSS Selectors to ignore these DOM elements during the visual check. ignoreSelectors = ["body div.test", "#sidebar"] ### Only screenshot a specific selector Pass a CSS selector to take a screenshot of this specific element only. selector = "body div.test" Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/results # Results of a failing Visual Test When a visual test fails, you will see 3 images on the visual test result page: - An image of the current screenshot - An image of the baseline screenshot (the screenshot that you approved) - A diff image, showcasing the difference between the two images above ### Diff image A diff image will show the difference between the two images. See an example of such a result below. ![Visual Test Diff](https://testingbot.com/assets/support/visual/codeless/diff-1e13f4e968c249e56c3030418f0e61fce8fd68c76686fc7b2d7332732ad2bcb5.webp) ## Results of a successful Visual Test A successful visual test will show both the current screenshot and the baseline image. The two images are identical. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/codeless # Codeless Visual Testing TestingBot provides codeless visual testing, allowing you to perform scheduled visual checks against any website, without writing any code. Simply add a URL to the webpage you'd like to test, pick the browsers you want to test on and indicate how frequently the test should run. TestingBot will open the webpage on the browsers you indicated and perform a visual pixel-by-pixel check. When TestingBot detects a mismatch, you will be alerted. ## Setup Please follow these steps to create your first codeless visual test: 1. Click the **Visual Testing** menu item in the member area 2. Choose **Schedule a visual test** 3. Enter the URL of the webpage you want to visually test ![Add codeless visual test](https://testingbot.com/assets/support/visual/codeless/edit-758f0f36126b9487b7708d6b364225783a3714edbf64cba9c2077464ba758194.webp) ## Select Browsers You'll need to select one or more browsers before you can start the visual test. A maximum amount of 5 different browser configurations is possible per test. You'll be able to choose between various platforms and browsers. Each browser runs on the latest version that is available to the general public. For every browser configuration, you can specify a screen resolution and a geographical location. ### Available platforms - Windows 7 - Windows 8 - Windows 8.1 - Windows 10 - Windows 11 - macOS Tahoe - macOS Sequoia - macOS Sonoma - macOS Ventura - macOS Monterey - iOS Simulators - Android Emulators ### Available browsers - Chrome + Mobile Chrome - Firefox - Safari + Mobile Safari - Microsoft Edge - Internet Explorer ## Schedule Visual Tests TestingBot allows you to specify a schedule when visual tests should run. You have various options to choose from: - Run once on a specific date and time - Run a visual test daily, at a specific time - Run the test on a weekly basis, on a specific number of days and a specific hour - Repeat the test every x minutes, on specific days and between specific hours - Use a [Cron Format](https://en.wikipedia.org/wiki/Cron) to specify when the test should run ![Schedule a codeless visual test](https://testingbot.com/assets/support/visual/codeless/schedule-b7e3d090ab158252ff773d5afddaff6e3e6004a457f8874ed5022d25e0eb9c92.webp) ## Alerting When a visual test fails, you can choose to be alerted immediately. ### Email Alert One or more e-mail addresses can be added to the alerting section of each test. As soon as a visual test fails, you'll be alerted through e-mail. The e-mail message will contain more details about what failed. The current screenshot will be shown, together with the baseline screenshot and a diff image (highlighting the differences between the baseline and the screenshot). ### SMS Alert You have the option to add your phone number, we will send you a text message when a visual test fails. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/automated # Automated Visual Testing TestingBot provides a Visual Regression Testing service which integrates directly with the following test frameworks: - [Appium](https://testingbot.com/support/visual-testing/automated/appium) - [Selenium](https://testingbot.com/support/visual-testing/automated/selenium) - [Playwright](https://testingbot.com/support/visual-testing/automated/playwright) - [Puppeteer](https://testingbot.com/support/visual-testing/automated/puppeteer) This visual testing functionality allows you to quickly and easily add visual checkpoints to your existing or newly created automated tests. TestingBot will take a screenshot of your website or app and perform a pixel-by-pixel scan, comparing it to a previous golden image. For every visual check you perform in your test, TestingBot will do the comparison and report back the results. Each result will be visible in the [TestingBot member area](https://testingbot.com/members), allowing you to compare the screenshot with the baseline. Your test scripts will be able to call a custom TestingBot command and receive back the comparison results instantly. This means you can have your tests instantly verify the UI results of your website and mobile apps. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/automated/selenium # Selenium Visual Testing Selenium is a browser automation framework, designed to automate browsers. While it is used for running functional cross browser tests, it lacks the ability to compare the UI of webpages across various browsers. TestingBot offers a visual regression testing feature which integrates in your existing or new Selenium WebDriver scripts. By adding one or more visual checks to your Selenium test, you can easily do UI comparison checks and detect visual regressions. ## Setup TestingBot introduces a new Javascript Executor command which you can use in your Selenium tests, called `tb:visual.snapshot`. Simply pass a unique identifier to this function and TestingBot will compare the current UI of the webpage with a previous baseline/golden image. When you run this command for the first time, a screenshot will be taken from the page and will be marked as the baseline. Any future calls with the same identifier will trigger a pixel comparison on TestingBot's end. If TestingBot detects the number of different pixels to be higher than the supplied threshold, the call will return a response indicating the UI has changed. To add the command to your Selenium tests, please see the example below, where we save a screenshot of the current page as `uniqueIdentifier`. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script('tb:visual.snapshot=uniqueIdentifier') ((JavascriptExecutor)driver).executeScript("tb:visual.snapshot=uniqueIdentifier"); $web_driver->executeScript('tb:visual.snapshot=uniqueIdentifier'); driver.execute_script('tb:visual.snapshot=uniqueIdentifier') await driver.executeScript('tb:visual.snapshot=uniqueIdentifier') ((IJavaScriptExecutor)driver).ExecuteScript("tb:visual.snapshot=uniqueIdentifier"); The identifier passed to `tb:visual.snapshot` is unique per browser vendor, not per browser version. TestingBot considers browser versions to generate identical UI's, whereas different browser vendors might generate slightly different UI's (for example Safari vs Chrome). Make sure you're always comparing against the same [screen-resolution](https://testingbot.com/support/web-automate/selenium/test-options#screenresolution) as the screen-resolution that was taken during the baseline capture. ## Visual Comparison Response Whenever you run a visual comparison during a Selenium test, you will receive back a response in less than 2 seconds. For each visual test, you will receive back a response indicating: - Does the screenshot match the baseline? - What are the number of pixels that are different between the two snapshots? - The URL to the result in the TestingBot dashboard - The visualId and runId of the visual test { "match": false, "pixelDifference": 341575, "url": "https://testingbot.com/members/visual/:visualId/runs/:runId", "visualId": ":visualId", "runId": ":runId" } Please see the example below on how to check whether a visual change was detected: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) visual_response = driver.execute_script('tb:visual.snapshot=uniqueIdentifier') visual_test_passed = visual_response["match"] == true String jsonString = (String) ((JavascriptExecutor) driver).executeScript("tb:visual.snapshot=uniqueIdentifier"); ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(jsonString); Boolean visualTestPassed = jsonNode.get("match").asBoolean(); } catch (Exception e) { e.printStackTrace(); } $visual_response = $web_driver->executeScript('tb:visual.snapshot=uniqueIdentifier'); $visual_json = json_decode($visual_response, true); $visual_test_passed = $visual_json["match"] === true; json_string = driver.execute_script("tb:visual.snapshot=uniqueIdentifier") # Decode the JSON response using the json module json_object = json.loads(json_string) # Check if the 'match' key is true visual_test_passed = json_object.get('match', False) const visual_response = await driver.executeScript('tb:visual.snapshot=uniqueIdentifier') const json_response = JSON.parse(visual_response) const visual_test_passed = json_response['match'] === true var jsonScript = "tb:visual.snapshot=uniqueIdentifier"; var jsonResult = (string)driver.ExecuteScript(jsonScript); var jsonObject = JsonConvert.DeserializeObject(jsonResult); var visualTestPassed = jsonObject != null && jsonObject.Matched ## Visual Baseline The first time you'll run the compare command, TestingBot will automatically mark the screenshot as the baseline. If you want to change the baseline after the first run, you can use the `tb:visual.baseline` command to take a new screenshot and set it as the baseline (golden image). You might want to use it to update the baseline when your webpage has changed its content or layout. Please see the example below on how to set the baseline to a new screenshot: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script('tb:visual.baseline=uniqueIdentifier') ((JavascriptExecutor) driver).executeScript("tb:visual.baseline=uniqueIdentifier"); $web_driver->executeScript('tb:visual.baseline=uniqueIdentifier'); driver.execute_script("tb:visual.baseline=uniqueIdentifier") await driver.executeScript('tb:visual.baseline=uniqueIdentifier') driver.ExecuteScript("tb:visual.baseline=uniqueIdentifier"); ## Visual Testing Options TestingBot provides various options to customize the visual comparison tests. Options can be passed with the `tb:visual.snapshot` command, for example: const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) await driver.executeScript(`tb:visual.baseline=${visualSnapshotJsonCmd}`) Option Name | Default Option Value | Description || `threshold` | `0.1` | This defines the color difference threshold (from 0 to 1). The smaller the number, the more precise the comparison will be. | | `antialiasing` | `true` | When this is set to `true`, TestingBot will not count antialiased pixels to the diff of the snapshot. | | `ignoreRegions` | `[]` | Regions to ignore, defined in pixel coordinates. Needs to be an array with these objects: [{ "x1": number, "y1": number, "x2": number, "y2": number }] | | `ignoreSelectors` | `[]` | Pass an array of CSS Selectors to ignore these DOM elements during the visual check. ["body div.test", "#sidebar"] | | `selector` | `-` | Pass a CSS selector to take a screenshot of this specific element only. If this is not specified, TestingBot will take a screenshot of the viewport. "body div.test" | | `fullpage` | `false` | If you'd like to take a screenshot of the entire page, specify `true`. TestingBot will capture the entire page, instead of only the viewport. This feature is currently only available for these browsers: Chrome, Microsoft Edge and Firefox. | [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) visual_snapshot_json_cmd = { name: 'testing123', options: { threshold: 0.3 } }.to_json driver.execute_script("tb:visual.baseline=#{visual_snapshot_json_cmd}") String visualSnapshotJsonCmd = "{\"name\": \"testing123\", \"options\": {\"threshold\": 0.3}}"; ((JavascriptExecutor) driver).executeScript("tb:visual.baseline=" + visualSnapshotJsonCmd); $visualSnapshotJsonCmd = json_encode([ 'name' => 'testing123', 'options' => [ 'threshold' => 0.3 ] ]); $driver->executeScript("tb:visual.baseline = '{$visualSnapshotJsonCmd}';"); visual_snapshot_json_cmd = json.dumps({ "name": "testing123", "options": { "threshold": 0.3 } }) driver.execute_script(f"tb:visual.baseline={visual_snapshot_json_cmd};") const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) await driver.executeScript(`tb:visual.baseline=${visualSnapshotJsonCmd}`) var visualSnapshotJsonCmd = "{\"name\": \"testing123\", \"options\": {\"threshold\": 0.3}}"; ((IJavaScriptExecutor)driver).ExecuteScript($"tb:visual.baseline={visualSnapshotJsonCmd};"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/automated/appium # Appium Visual Testing Appium is a mobile test automation framework, built to run web and mobile app tests on mobile simulators and physical devices. Visual testing is currently not yet supported by Appium. TestingBot has built a visual regression testing solution for Appium, which you can use without installing any plugins or custom code. By adding one or more visual checks to your Appium test, you can quickly add visual checkpoints to your Appium test scripts. TestingBot will let you know if a snapshot of your current app looks identical to the baseline that you've set. ## Setup TestingBot added a new Javascript Executor command which can be used in Appium tests, called `tb:visual.snapshot`. By passing a unique identifier with this command, TestingBot will compare the initial screenshot taken with this identifier to the current screenshot. TestingBot will perform a pixel comparison scan, comparing the screenshot of your mobile app or website with the original golden image (baseline). If TestingBot detects the number of different pixels to be higher than the supplied threshold, the test will be marked as failed. To add one or more visual checks to your Appium tests, please see the example below, where we save a screenshot of the current mobile app/website state as `uniqueIdentifier`. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script('tb:visual.snapshot=uniqueIdentifier') ((JavascriptExecutor)driver).executeScript("tb:visual.snapshot=uniqueIdentifier"); $web_driver->executeScript('tb:visual.snapshot=uniqueIdentifier'); driver.execute_script('tb:visual.snapshot=uniqueIdentifier') await driver.executeScript('tb:visual.snapshot=uniqueIdentifier') ((IJavaScriptExecutor)driver).ExecuteScript("tb:visual.snapshot=uniqueIdentifier"); ## Visual Comparison Response During your Appium test, you can perform one or more visual comparisons and receive back a response in less than 2 seconds. For each visual test, you will receive back a response indicating: - Does the screenshot match the baseline? - What are the number of pixels that are different between the two snapshots? - The URL to the result in the TestingBot dashboard - The visualId and runId of the visual test { "match": false, "pixelDifference": 341575, "url": "https://testingbot.com/members/visual/:visualId/runs/:runId", "visualId": ":visualId", "runId": ":runId" } Please see the example below on how to check whether a visual change was detected: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) visual_response = driver.execute_script('tb:visual.snapshot=uniqueIdentifier') visual_test_passed = visual_response["match"] == true String jsonString = (String) ((JavascriptExecutor) driver).executeScript("tb:visual.snapshot=uniqueIdentifier"); ObjectMapper objectMapper = new ObjectMapper(); try { JsonNode jsonNode = objectMapper.readTree(jsonString); Boolean visualTestPassed = jsonNode.get("match").asBoolean(); } catch (Exception e) { e.printStackTrace(); } $visual_response = $web_driver->executeScript('tb:visual.snapshot=uniqueIdentifier'); $visual_json = json_decode($visual_response, true); $visual_test_passed = $visual_json["match"] === true; json_string = driver.execute_script("tb:visual.snapshot=uniqueIdentifier") # Decode the JSON response using the json module json_object = json.loads(json_string) # Check if the 'match' key is true visual_test_passed = json_object.get('match', False) const visual_response = await driver.executeScript('tb:visual.snapshot=uniqueIdentifier') const json_response = JSON.parse(visual_response) const visual_test_passed = json_response['match'] === true var jsonScript = "tb:visual.snapshot=uniqueIdentifier"; var jsonResult = (string)driver.ExecuteScript(jsonScript); var jsonObject = JsonConvert.DeserializeObject(jsonResult); var visualTestPassed = jsonObject != null && jsonObject.Matched ## Visual Baseline The first time that you run the compare command with a given identifier, TestingBot will automatically mark the screenshot as the baseline. If you want to update the baseline after it has already been saved, you can use the `tb:visual.baseline` command to take a new screenshot and set it as the new baseline image. Please see the example below on how to update the baseline for a given identifier: [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) driver.execute_script('tb:visual.baseline=uniqueIdentifier') ((JavascriptExecutor) driver).executeScript("tb:visual.baseline=uniqueIdentifier"); $web_driver->executeScript('tb:visual.baseline=uniqueIdentifier'); driver.execute_script("tb:visual.baseline=uniqueIdentifier") await driver.executeScript('tb:visual.baseline=uniqueIdentifier') driver.ExecuteScript("tb:visual.baseline=uniqueIdentifier"); ## Visual Testing Options TestingBot offers various options to customize the visual comparison tests. Options can be passed with the `tb:visual.snapshot` command: const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) driver.executeScript(`tb:visual.baseline=${visualSnapshotJsonCmd}`) Option Name | Default Option Value | Description || `threshold` | `0.1` | This defines the color difference threshold (from 0 to 1). The smaller the number, the more precise the comparison will be. | | `antialiasing` | `true` | When this is set to `true`, TestingBot will not count antialiased pixels to the diff of the snapshot. | | `ignoreRegions` | `[]` | Regions to ignore, defined in pixel coordinates. Needs to be an array with these objects: [{ "x1": number, "y1": number, "x2": number, "y2": number }] | | `ignoreSelectors` Web Testing Only | `[]` | Pass an array of CSS Selectors to ignore these DOM elements during the visual check. ["body div.test", "#sidebar"] | | `selector` Web Testing Only | `-` | Pass a CSS selector to take a screenshot of this specific element only. If this is not specified, TestingBot will take a screenshot of the viewport. "body div.test" | [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[Python](https://testingbot.com#)[C#](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) visual_snapshot_json_cmd = { name: 'testing123', options: { threshold: 0.3 } }.to_json driver.execute_script("tb:visual.baseline=#{visual_snapshot_json_cmd}") String visualSnapshotJsonCmd = "{\"name\": \"testing123\", \"options\": {\"threshold\": 0.3}}"; ((JavascriptExecutor) driver).executeScript("tb:visual.baseline=" + visualSnapshotJsonCmd); $visualSnapshotJsonCmd = json_encode([ 'name' => 'testing123', 'options' => [ 'threshold' => 0.3 ] ]); $driver->executeScript("tb:visual.baseline = '{$visualSnapshotJsonCmd}';"); visual_snapshot_json_cmd = json.dumps({ "name": "testing123", "options": { "threshold": 0.3 } }) driver.execute_script(f"tb:visual.baseline={visual_snapshot_json_cmd};") const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) await driver.executeScript(`tb:visual.baseline=${visualSnapshotJsonCmd}`) var visualSnapshotJsonCmd = "{\"name\": \"testing123\", \"options\": {\"threshold\": 0.3}}"; ((IJavaScriptExecutor)driver).ExecuteScript($"tb:visual.baseline={visualSnapshotJsonCmd};"); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/automated/puppeteer # Puppeteer Visual Testing Using TestingBot's Puppeteer Visual Testing command, you will be able to take screenshots during your Puppeteer tests and compare these with baselines. You will see these results in the TestingBot member area, with additional details such as match percentage, a diff of the image and more useful information. For each screenshot taken during your Puppeteer test, TestingBot will perform a pixel-by-pixel comparison with the baseline image. If a mismatch is detected, your test will fail. ## Setup TestingBot added a new `page.evaluate` command which can be used in your Puppeteer tests. Simply pass a ``testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`` argument to have TestingBot take and compare the screenshot. TestingBot will perform a pixel comparison scan, comparing the screenshot of your website with the original golden image (baseline). If TestingBot detects the number of different pixels to be higher than the supplied threshold, the test will be marked as failed. const results = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`) In the example above, the screenshot will be saved as `uniqueIdentifier`. Any future calls will compare the screenshot with the screenshot that was saved the first time this command was run. ## Visual Comparison Response Every time you run a `visual.snapshot` command, TestingBot will return back the visual comparison result in less than 2 seconds. The response will contain the following information: - Does the screenshot match the baseline? - What are the number of pixels that are different between the two snapshots? - The URL to the result in the TestingBot dashboard - The visualId and runId of the visual test { "match": false, "pixelDifference": 341575, "url": "https://testingbot.com/members/visual/:visualId/runs/:runId", "visualId": ":visualId", "runId": ":runId" } Please see the example below on how to check whether a visual change was detected: const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`) const json_response = JSON.parse(visual_response) const visual_test_passed = json_response['match'] === true ## Visual Baseline To set a new baseline for your snapshots, you can use the following command: const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.baseline', arguments: { name: 'uniqueIdentifier' }})}`) ## Visual Testing Options TestingBot offers various options to customize the visual comparison tests. Options can be passed with the `visual.snapshot` command: const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: visualSnapshotJsonCmd })}`) Option Name | Default Option Value | Description || `threshold` | `0.1` | This defines the color difference threshold (from 0 to 1). The smaller the number, the more precise the comparison will be. | | `antialiasing` | `true` | When this is set to `true`, TestingBot will not count antialiased pixels to the diff of the snapshot. | | `ignoreRegions` | `[]` | Regions to ignore, defined in pixel coordinates. Needs to be an array with these objects: [{ "x1": number, "y1": number, "x2": number, "y2": number }] | | `ignoreSelectors` | `[]` | Pass an array of CSS Selectors to ignore these DOM elements during the visual check. ["body div.test", "#sidebar"] | | `selector` | `-` | Pass a CSS selector to take a screenshot of this specific element only. If this is not specified, TestingBot will take a screenshot of the viewport. "body div.test" | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/visual-testing/automated/playwright # Playwright Visual Testing While [Playwright Visual Regression Testing](https://testingbot.com/support/web-automate/playwright/visual-regression-testing) is already included with Playwright Test, TestingBot now offers a visual comparison feature for all automated tests. Using TestingBot's visual command, you will be able to take screenshots during your Playwright tests and compare these with baselines. You will see these results in the TestingBot member area, with additional details such as match percentage, a diff of the image and more useful information. ## Setup TestingBot added a new `page.evaluate` command which can be used in your Playwright tests. Simply pass a ``testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`` argument to have TestingBot take and compare the screenshot. TestingBot will perform a pixel comparison scan, comparing the screenshot of your website with the original golden image (baseline). If TestingBot detects the number of different pixels to be higher than the supplied threshold, the test will be marked as failed. const results = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`) In the example above, the screenshot will be saved as `uniqueIdentifier`. Any future calls will compare the screenshot with the screenshot that was saved the first time this command was run. ### Full Playwright Example Below is a full example on how to run a visual Playwright test on TestingBot's browser cloud. const playwright = require('playwright-core') (async () => { const browser = await playwright.chromium.connectOverCDP({ endpointURL: 'wss://cloud.testingbot.com/?key=key&secret=secret&browserName=chrome&browserVersion=latest', }) const page = await browser.newPage() await page.goto('https://testingbot.com') const results = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`) console.log(results) await browser.close() })(); Visual testing with Playwright on TestingBot's browser cloud currently only works with Chromium-based browsers (Chrome, Microsoft Edge) through `connectOverCDP`. ## Visual Comparison Response Every time you run a `visual.snapshot` command, TestingBot will return back the visual comparison result in less than 2 seconds. The response will contain the following information: - Does the screenshot match the baseline? - What are the number of pixels that are different between the two snapshots? - The URL to the result in the TestingBot dashboard - The visualId and runId of the visual test { "match": false, "pixelDifference": 341575, "url": "https://testingbot.com/members/visual/:visualId/runs/:runId", "visualId": ":visualId", "runId": ":runId" } Please see the example below on how to check whether a visual change was detected: const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: { name: 'uniqueIdentifier' }})}`) const json_response = JSON.parse(visual_response) const visual_test_passed = json_response['match'] === true ## Visual Baseline To set a new baseline for your snapshots, you can use the following command: const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.baseline', arguments: { name: 'uniqueIdentifier' }})}`) ## Visual Testing Options TestingBot offers various options to customize the visual comparison tests. Options can be passed with the `visual.snapshot` command: const visualSnapshotJsonCmd = JSON.stringify({ name: 'testing123', options: { threshold: 0.3 } }) const visual_response = await page.evaluate(_ => {}, `testingbot_executor: ${JSON.stringify({action: 'visual.snapshot', arguments: visualSnapshotJsonCmd })}`) Option Name | Default Option Value | Description || `threshold` | `0.1` | This defines the color difference threshold (from 0 to 1). The smaller the number, the more precise the comparison will be. | | `antialiasing` | `true` | When this is set to `true`, TestingBot will not count antialiased pixels to the diff of the snapshot. | | `ignoreRegions` | `[]` | Regions to ignore, defined in pixel coordinates. Needs to be an array with these objects: [{ "x1": number, "y1": number, "x2": number, "y2": number }] | | `ignoreSelectors` | `[]` | Pass an array of CSS Selectors to ignore these DOM elements during the visual check. ["body div.test", "#sidebar"] | | `selector` | `-` | Pass a CSS selector to take a screenshot of this specific element only. If this is not specified, TestingBot will take a screenshot of the viewport. "body div.test" | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations # TestingBot Integrations Below is an overview of the several integrations with TestingBot we provide: - [App Center](https://testingbot.com/support/integrations/appcenter) - [Appium Inspector](https://testingbot.com/support/integrations/appium-desktop) - [Bitrise](https://testingbot.com/support/integrations/ci-cd/bitrise) - [Bugsnag](https://testingbot.com/support/integrations/bugsnag) - [Cerberus](https://testingbot.com/support/integrations/cerberus) - [GitHub Actions](https://testingbot.com/support/integrations/ci-cd/github-actions) - [Jenkins CI](https://testingbot.com/support/integrations/ci-cd/jenkins) - [Jira](https://testingbot.com/support/integrations/jira) - [Katalon Studio](https://testingbot.com/support/integrations/katalon-studio) - [QMetry](https://testingbot.com/support/integrations/qmetry) - [Ranorex Studio](https://testingbot.com/support/integrations/ranorex) - [Slack](https://testingbot.com/support/integrations/slack) - [TeamCity CI](https://testingbot.com/support/integrations/ci-cd/teamcity) - [Tricentis Tosca](https://testingbot.com/support/integrations/tricentis-tosca) - [Webhooks](https://testingbot.com/support/integrations/webhooks) - [Zebrunner](https://testingbot.com/support/integrations/zebrunner) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/appcenter # Visual Studio App Center [Visual Studio App Center](https://appcenter.ms/) is a Microsoft product that allows you to build your mobile apps in the cloud. Simply connect your repository and App Center will build your app on every commit. This integration allows you to test builds generated by App Center on our mobile device cloud. In this guide we'll show you: - How to connect to the Visual Studio App Center API. - Fetch the public link to the latest build. - Upload the build to [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload) for testing. ## Retrieve API Token To get started, you'll need to log into [Visual Studio App Center](https://appcenter.ms/) and generate an API key. - Sign into your App Center account. - Go to **Account Settings** and choose **User API Tokens**. - Click the **New API Token** button. - Add a description for your token, for example **TestingBot-Token**. - Give the token **Read Only** access. - Generate and copy the API Token. ![Visual Studio App Center API Token](https://testingbot.com/assets/support/appcenter/token-850b6e80bb9e0adc12f0798d19539bdb7c3837ff34847d8a8d0808397037b90b.png) ## List All App Projects Now that we have an API token, we can use it to fetch all app projects: curl -sX GET "https://api.appcenter.ms/v0.1/apps" \ -H "Content-Type: application/json" \ -H "X-Api-Token: [YOUR-API-TOKEN]" The response should be similar to this: [ { "id":"9c22426b-e23e-4389-9f4a-08ec2eb9e656", "app_secret":"3da37025-4548-4abe-8979-c0f097816e51", "description":null, "display_name":"testingbot-demo", "name":"testingbot-demo", "os":"Android", "platform":"React-Native", "origin":"appcenter", "icon_url":null, "created_at":"2020-08-19T08:39:21.000Z", "updated_at":"2020-08-19T08:39:21.000Z", "release_type":null, "owner":{ "id":"4a05e941-f5be-4cfe-8b25-3887a768578f", "avatar_url":null, "display_name":"TestingBot", "email":"...", "name":"testingbot", "type":"user" }, "azure_subscription":null, "member_permissions":["manager"] }, { ... }] ## Fetch build info from API Now we can fetch the build information from the App Center API. We'll need the **name** and **owner.name** from the previous response: If you want to fetch the build of the latest release, please use: curl -sX GET "https://api.appcenter.ms/v0.1/apps/[owner.name]/[name]/releases/latest" \ -H "Content-Type: application/json" \ -H "X-Api-Token: [YOUR-API-TOKEN]" If you are looking to fetch the latest build (not necessarly released yet), please use: curl -sX GET "https://api.appcenter.ms/v0.1/apps/[owner.name]/[name]/branches/master/builds" \ -H "Content-Type: application/json" \ -H "X-Api-Token: [YOUR-API-TOKEN]" Then copy the build id and use: curl -sX GET "https://api.appcenter.ms/v0.1/apps/[owner.name]/[name]/builds/[build-id]/downloads/build" \ -H "Content-Type: application/json" \ -H "X-Api-Token: [YOUR-API-TOKEN]" The response should contain a URL which points to the build, similar to this example: {"uri":"https://build.appcenter.ms/v0.1/public/apps/9c22426b-e23e-4389-9f4a-oefkoe/downloads?token=6663fc99b13e70dsfds856c8a302e9d7398fkjecfc72b0c133bcf4035"} ## Upload build Now that you've retrieved the build URL, you can upload this build to [TestingBot Storage](https://testingbot.com/support/app-automate/help/upload). curl -X POST "https://api.testingbot.com/v1/storage" \ -u key:secret -d "url=[BUILD-URL]" This will return a unique URL `{"app_url": "tb://..."}` which you can use with your tests. Simply add the `tb://...` as an **app** capability to run your tests: [more information](https://testingbot.com/support/app-automate/help/upload). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/appium-desktop # Appium Inspector With [Appium Inspector](https://github.com/appium/appium-inspector) (previously known as Appium Desktop) you can visualize and inspect all the different elements in your mobile app. Locate XPaths and element identifiers by selecting the elements in the live view. Appium Inspector will show a live feed of the app. When you click an element it will show the possible locators for the specific element. This is a great help when developing or updating automated mobile app tests. TestingBot has a built-in integration with Appium Inspector. Simply paste your TestingBot `key` and `secret` in the TestingBot configuration setting (see below). ## Add TestingBot Select TestingBot from the **Cloud Providers** tab. A new TestingBot tab will appear. ![Appium Inspector with TestingBot](https://testingbot.com/assets/support/appium-desktop/overview-a331c33f7482b169896f85c37e8d06c2f628949cc57514005f70b1b6fb24e173.png) ## Configuration Next, you can fill in your TestingBot `KEY` and `SECRET`. This will be used to authenticate with our Appium grid. You can then fill in the desired capabilities, which are necessary to connect to a device in our grid. ![Appium Inspector with TestingBot](https://testingbot.com/assets/support/appium-desktop/capabilities-096bfa37f18a36513e6946f3e7be3251e91376dc525a5d0d8043e79266efeb2b.png) ## Inspect Once your session has started, you will see a live view of the device on the left and the possible locators for the selected element on the right. ![Appium Inspector with TestingBot](https://testingbot.com/assets/support/appium-desktop/inspect-d3fa2f26e7e45a864f38690862747d7c65e48eb90847794d8a91749f9cfc98f7.png) ## TestingBot Options To specify [TestingBot specific options](https://testingbot.com/support/app-automate/appium/options), please use `tb:options` as field name and `JSON Object` as field type. ![Appium Inspector with TestingBot](https://testingbot.com/assets/support/appium-desktop/options-a56030507f0b62f4765a145c14b9cfc17ed164a49d68d683a61aa9a4ebbc798b.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/bugsnag # Bugsnag Integration Create issues in Bugsnag straight from TestingBot, during manual web and mobile app testing. Report any browser or device issue straight to Bugsnag, with screenshots and details. ## Features Adding this integration will allow you to share issues you've noticed during manual testing. - During manual testing on TestingBot, you can take a screenshot of the issue. - Annotate the screenshot to highlight the problem. - Post the screenshot, together with a description of the issue straight to your Bugsnag Project. - Team members on Bugsnag will see the issue listed in Bugsnag. ## Getting Started To get started, please follow these steps: - Log in to Bugsnag and click the **Settings** icon - Open the **Project Settings**. You project settings will contain a **Notifier API key** , which you can copy and enter in the [Bugsnag Settings Form](https://testingbot.com/members/integrations/bugsnag) on TestingBot. ![Bugsnag Key](https://testingbot.com/assets/support/integrations/bugsnag/bugsnag_key-7174452f1756f55696f810b7ab7a8fd3c43056aab9b182d0a8f00e98f94737ac.webp) ## Report Issues - During a manual testing session, you can click the **Photo** option to take a live screenshot of the page. - You can annotate the screenshot to make the issue more clear, with a set of paint tools in the screenshot editor. - Finally, click the **Share** button to see a list of services. Click Bugsnag to send the issue to your Bugsnag project. - Enter a title and a description of the issue. The screenshot will be included automatically. ![Bugsnag Issue](https://testingbot.com/assets/support/integrations/bugsnag/issue-3841d11b0c3e830f99f7c77482f1e09a84247d59710f22a77cf1b33b49d5ffa2.webp) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/cerberus # Setting up TestingBot as the Executor Robot Cerberus Testing is a low-code test automation platform that supports testing Web, iOS and Android. This guide will help you with running tests on TestingBot from the Cerberus Testing Framework. Inside your Cerberus Testing instance you will need to set up TestingBot as your Test Executor. Please follow the steps below to set this up. 1. Click on **Run** and then click **Robot**. Next, click the button **Create new Robot**. ![Cerberus new Robot](https://testingbot.com/assets/support/integrations/cerberus/1-1c34e36c958ed167eb761cf229bfe90fbc631860acf820a158b0c16c421da764.webp) 2. Configure the Robot with the browser you want to test on, specify a version and operating system and give it a name, for example TestingBot-Robot. ![Cerberus TestingBot Robot](https://testingbot.com/assets/support/integrations/cerberus/2-c3d048385859c37a530b2a486bada42707ca6f1a11f8d9d53c8b213070a06712.webp) 3. Next, click **Executors** and specify these details: - **Host** : `hub.testingbot.com` - **Port** : `80` - **Host User** : your TestingBot key - **Host Password** : your TestingBot secret ![Cerberus TestingBot Robot](https://testingbot.com/assets/support/integrations/cerberus/3-b441e18a51ad28cb7efa767f985b6ac1c06200f47ea5136cfa43b4609a853f5e.webp) 4. Now it's time to run a test. Click **Run** and **Run Test Case** , then select a test case to run. ![Cerberus Run Test](https://testingbot.com/assets/support/integrations/cerberus/4-fb2061ae037a195cefe192f616b4ffab0de9e8a6451b69af04a5b96df799542b.webp) 5. Choose an environment, for example **PROD**. ![Cerberus Environment](https://testingbot.com/assets/support/integrations/cerberus/5-6f646e15df72c13324a2b8ff5eb62e75b4b713f94628df23c0e06defb04f2589.webp) 6. In the Robot settings, select the TestingBot-Robot you created earlier. ![Cerberus Robot Settings](https://testingbot.com/assets/support/integrations/cerberus/6-b9faea4d9562f9213492857d08f8723c9e5ef67bca2de7d7a1c6d291d7748340.webp) 7. Run the test, you should see a success message once the test has finished running. Test details, together with screenshots and a video will be available in your TestingBot member area. ![Cerberus Run test](https://testingbot.com/assets/support/integrations/cerberus/7-22cdac8272c56f09c7c8d1cff8665581e1e407d8e0eb2ee38588bc46ba90f25f.webp) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/jira # Jira Integration Enable Jira integration to easily create Jira issues from your TestingBot member area. This integration allows you to embed test details and assets in your Jira tickets. ## Setup Jira To get started, please go to [Members \> Integrations](https://testingbot.com/members/integrations) and click **Jira**. You will be asked to fill in the `e-mai address` you used to log in with, a `password` and `host` of your Jira Instance. We recommend generating and using an `API Token` and using the API token instead of the password, for increased security. ![Jira Integration](https://testingbot.com/assets/support/integrations/jira/jira1-0388f274e6c5643e42dca8a74da3a5cd93fa2dca8c6d1149821bd64c8f84a3bf.png) ## Share a Test Once the Jira configuration is completed, you can share any Automated Test from the Test Detail page. Simply click **Jira** as share option. ![Jira Integration](https://testingbot.com/assets/support/integrations/jira/jira2-303efd5762b5b1ab564bda9fc531ee490b5cc93d3dd71c1cf64ba08233fa1cc1.png) A form will appear asking you to fill in `Jira Project`, `Jira IssueType`, `Title` and `Description`. The description will be pre-filled with the test meta-data. ![Jira Integration](https://testingbot.com/assets/support/integrations/jira/jira3-be7943ac21953004439242f21dd957c5a1905835efcfcd6427e2aa7e35285b15.png) Once you click **Share** the Jira ticket will be created in your Jira instance. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/katalon-studio # Katalon Studio Plugin TestingBot has a [Katalon Studio Plugin](https://store.katalon.com/product/155/TestingBot-Integration) available in the Katalon Store. ## Install Plugin Navigate to the [plugin page](https://store.katalon.com/product/155/TestingBot-Integration), and click **Install Plugin**. The plugin will be added to your Katalon Studio. ## Configure Plugin Once installed, go to **Project \> Settings**. Under the Plugins section, you will see the TestingBot Integration plugin. Fill in the TestingBot `KEY` and `SECRET`, together with the desired capabilities you want to test. ![Katalon Studio + TestingBot](https://testingbot.com/assets/support/katalon/katalon1-e886ffe2cff674d78c9cebd21e80e7534cb825c4e1adc2d3a95e9815c684abe4.png) ## Run Test To run the test on TestingBot: - Click the Run button `(Command + Shift + A)` - Select Custom capabilities - Select the TestingBot profile ![Katalon Studio + TestingBot](https://testingbot.com/assets/support/katalon/katalon2-1fdf4a496b469d06c2e805c89330147f27184eb426846b64a9b74da4f8bc2c5f.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/qmetry # QMetry QMetry Automation Studio offers multi-language scripting to automated testing. The product provides partial codeless automation, targetted to manual users or beginners. The framework offers a test recorder which allows users to record test cases and generate code. This guide documents how to use QMetry with TestingBot to run automated tests on various platforms. ## Configuration To get started with running a cloud test using QMetry, you'll need to specify some settings: 1. Add `driver.name=remotedrivername` in either **application.properties** , **env.properties** or **testrun\_config.xml** Where `remotedrivername` is either **chromeRemoteDriver** , **firefoxRemoteDriver** or another valid remote drivername. 2. Set the `remote.server` to use the TestingBot Hub: 3. Specify the capabilities for your test. You'll need to specify this in the same file. 4. Update the `driver.name` parameter in `web.config` 5. You can now run the test from the command line. The test will run on the TestingBot browser grid. ## TestingBot Tunnel You can use [TestingBot Tunnel](https://testingbot.com/support/tunnel) to test websites that are not publicly available. For example a webpage on your staging server, or local computer. To get started, please see the steps below: - Download and run [TestingBot Tunnel](https://testingbot.com/support/tunnel) with a specific tunnel identifier that you chose: - Now you will need to specify the same `tunnel-identifier` in the capabilities, to let TestingBot know it should use the tunnel you just created: Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ranorex # Integrate TestingBot with Ranorex Ranorex is a GUI test framework, designed to execute tests. Using Ranorex Studio, you can easily manage and record tests, in your local browser. Without writing any code, you can create advanced Selenium WebDriver test cases. This guide will help you in setting up a connection between Ranorex Studio and TestingBot, allowing you to run tests created with Ranorex on TestingBot's remote browser grid. ## Getting started with Ranorex 1. Start Ranorex Studio and click the **Web** tab in the wizard to create a new Web test. 2. Provide the Solution name and Directory Location to store this new Project, then click **Continue**. 3. Specify the URL of the website you'd like to test and choose a browser in the next screen. Next, click **Continue**. 4. Select **Do not use whitelisting** as recording behavior. 5. Select **Finish** to complete this solution. ## Setting up TestingBot Endpoint in Ranorex Studio Before you can run a Ranorex Studio test on TestingBot, we'll first have to set up TestingBot as an endpoint. To do this, please follow the steps below. 1. To run the test on TestingBot's remote browser grid, add the TestingBot endpoint by selecting **View** in the menubar, then click **Endpoints**. Or type `Ctrl+Alt+P`. 2. In the dialog that appears, click the **Add endpoint** button. 3. Select **WebDriver** as the Endpoint type. As the Endpoint name, you can fill in TestingBot. The address should be `https://hub.testingbot.com/wd/hub`. Finally, click the **Add endpoint** button. 4. You have now successfully added TestingBot as an Endpoint. Click the icon next to TestingBot's endpoint to activate it (making it green). ## Executing Ranorex tests on TestingBot 1. You will need to add the necessary capabilities to the Endpoint's **Capabilities JSON** section. To do this, right click the TestingBot connector and click **View details**. 2. Add the following capabilities in **Capabilities JSON section** and add a name in the Name field. Finally, click the **Save** button. 3. Now mark the configuration you just created as the **Active configuration**. 4. Before we can run tests, we will need to increase the default timeout value of 10 seconds. To do this, open the settings by clicking the **Open Settings** button. 5. With the Settings window open, click the **Plugins** tab and scroll to the **WebDriver** section, where you will see a **WebDriver command timeout** value of 10. 6. To run a test, make sure you've selected the TestingBot endpoint. 7. You can now run your Ranorex test on TestingBot. Click the **Run** button. Once the test has finished, you will see it appear in the TestingBot dashboard with a video, logs and other metadata. ## Testing privately hosted websites with Ranorex and TestingBot TestingBot allows you to run automated tests on internal development environments such as staging URLs or localhost. To get started, please make sure you've downloaded [TestingBot Tunnel](https://testingbot.com/support/tunnel). You can start the tunnel through the commandline: java -jar testingbot-tunnel.jar key secret --tunnel-identifier ranorexTunnel Next, you will need to edit the **Capabilities JSON** configuration in the custom TestingBot endpoint you've created and add a `tunnelIdentifier` in the `tb:options` JSON object. { "tb:options": { "key":"....", "secret":"...", "tunnelIdentifier": "ranorexTunnel" } } ## Passing custom capabilities with Ranorex Studio TestingBot provides various [custom capabilities](https://testingbot.com/support/web-automate/selenium/test-options) to configure test runs, such as changing the `browserName`, `version`, `platform` and more. To include these with your test, make sure to edit the **Capabilities JSON** configuration in the custom TestingBot endpoint you've created. { "browserName": "chrome", "browserVersion": "latest", "platformName": "WIN10", "tb:options": { "key":"....", "secret":"...", "screen-resolution": "1280x1024", "name": "Ranorex Test" } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/slack # Slack Integration Add the Slack TestingBot app to your workspace to integrate TestingBot with your Slack Workspace. ## Features Once you've added the [TestingBot Slack App](https://slack.com/apps/A9L319MDY-testingbot) to your Slack workspace, these features will become available: - Our Slack Bot can **post when a test finishes, succeeds or fails.** - **Slash commands** : see Test Analytics, Builds and other test-metadata straight from inside Slack. - **Unfurl URLs** : paste a TestingBot test URL in your Slack channel and our bot will add extra meta-data to the post. - **Share test-results** with other Slack members. - **Chat** with our Slack TestingBot App. ## Getting Started To get started, please log in and go to the [Slack Integration page](https://testingbot.com/members/integrations/slack). You will see a button "Add to Slack" which redirect to the slack.com website. There, you will be asked to add the TestingBot app to your workspace. Pick which channel you'd like our TestingBot app to join. ![Setup Slack Integration](https://testingbot.com/assets/support/slack/setup-4e4f827f057250cb4e0fd5fe6552c7ed72c7f7ebe62c943d96ff758e42d73161.png) ## Test Events Once you've added the TestingBot app to your Slack workspace, you can specify if you'd like to be notified when a test on TestingBot succeeds or fails. For example: as soon as a test fails, our bot will post to the Slack channel you specified. The notification will include test meta-data and a direct link to the test where you can see a video recording, logs and screenshots of the test. To specify for which events you'd like to be notified, please go to the [Slack Settings page](https://testingbot.com/members/integrations/slack) in our member area. There you'll be able to specify if and when we should send Test-Events to your Slack channel. - Send a message to your Slack channel when a test finishes - Send a message to your Slack channel, but only when a test succeeds - Send a message to your Slack channel, but only when a test fails You can optionally set a condition to only send out these Slack events for a [specific group](https://testingbot.com/support/web-automate/selenium/test-options#grouping). ## Slack Commands The TestingBot app will add the following commands to your Slack workspace: - /tests Retrieves an overview of your most recent tests. For each test you can see if it passed or failed, how long it took and on which platform it ran. You can specify a specific day to only show tests for that day. These are the possible arguments you can specify: - today - yesterday - week (last 7 days) - month (last 31 days) - 2026-01-16 format - /test Shows details for a single test. Details include test duration, success state, a screenshot and which platform the test was run on. - /builds Shows an overview of the most recent builds. How many tests succeeded in the build, how many failed. A link is included to directly go the build overview page. - /build Shows details for a single build. Specify the build-identifier. For example: /build my-build-identifier ## Unfurl URLs When you or your colleagues on Slack post a TestingBot URL, and the URL links to a test result, then the TestingBot Slack app will automatically add test meta-data to the link. Test meta-data includes: - Which browser/platform the test ran on - Whether the test succeeded or failed - A screenshot of the test - How long the test took to run ## Private Channels To use our Slack bot in a private channel, please Add the app manually to your private channel. Click the name of your private channel, then choose **Add an app**. Once you've added the app, our Slackbot will be able to communicate in your private channel. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/tricentis-tosca # TestingBot and Tricentis Tosca [Tricentis Tosca](https://www.tricentis.com/products/automate-continuous-testing-tosca) is an industry-leading test creation tool, that allows for testing of websites and mobile apps. By connecting to TestingBot from within Tosca Commander, you will be able to run your tests in parallel on remote browsers and devices. To get ready, please make sure you have downloaded and installed Tosca. Next, you'll need a TestingBot account to pass your TestingBot key and secret credentials to Tosca. ## Running tests on TestingBot With Tosca Commander open, make sure you have created or recorded some web test cases. For a specific test case, go to the **Test configuration** tab, and make sure these test configuration parameters are listed: - **Browser** : set this to Chrome, Firefox, Edge or another browser - **OperatingSystem** : for example `WIN10`, `WIN11` or [other platforms](https://testingbot.com/support/web-automate/browsers) - **HubAddress** : set this to `https://TB_KEY:TB_SECRET@hub.testingbot.com/wd/hub`, where you replace `TB_KEY` with your actual TestingBot key and `TB_SECRET` with your actual TestingBot secret, obtained from the member area ![Tosca Configuration](https://testingbot.com/assets/support/integrations/tosca/config-aaf0eb391f94110e69124271012085d2173eb54861b887e47349a8e6500793f1.webp) ### Set Desired Capabilities With the [Set Desired Capabilities](https://documentation.tricentis.com/tosca/2410/en/content/engines_3.0/mobile/tbox_mobileweb_set_appium_capabilities.htm) module you can specify multiple capabilities to target and customize tests on TestingBot. Make sure to use this module at the start of your test(s). The **Set Desired Capabilities module** is part of the Standard subset. You can find it under `Standard modules->TBox XEngines->Mobile`. ![Tosca Set Desired Capabilities](https://testingbot.com/assets/support/integrations/tosca/capabilities-module-88cb4211690cbbe02bed828785ffe38ff103b3c772e50c41038c1935ae8b231c.webp) You will need to specify the `AppiumServer` option, specifying the TestingBot Grid endpoint `https://hub.testingbot.com/wd/hub`. ![Tosca AppiumServer](https://testingbot.com/assets/support/integrations/tosca/appium-server-fb43069ff59a569cef71aefa870a7db977e9069d64713673e1e09b0b0f9a1eeb.webp) You can specify the `Fibermode = true` option to improve the performance of remote WebDriver and Tosca. It will decrease the amount of communication that is required between Tosca and TestingBot, improving overall performance. ### TestingBot Storage You can run mobile app tests with Tosca on TestingBot's mobile devices, by specifying for example a [TestingBot Storage URL](https://testingbot.com/support/api#upload). You can add a `.apk` or `.ipa` extensions to the `tb://` URLs, to make sure Tosca accepts these URLs. ![Tosca TestingBot Storage](https://testingbot.com/assets/support/integrations/tosca/tb-url-865a51ae63ffe7f82cdf889dd3d8a860cf4f4611b15cc16ccb0b3703599f03cf.webp) ## Scanning a Mobile App Tosca Commander provides a way to scan a mobile iOS or Android app. You can use this on a remote iOS or Android device running on TestingBot. 1. In Tosca Commander, on the **Modules** tab, click **Scan** and then click **Mobile**. 2. In the **Add connection** input, enter `https://hub.testingbot.com/wd/hub` as Appium Server Address. Choose **Cloud (Appium)** as type. 3. In the **Add device** input field, enter the information for the TestingBot device you want to use. For example, **Pixel 8**. 4. In the **Edit native/hybrid application input** , enter the URL to the app you want to test, or supply the [TestingBot Storage](https://testingbot.com/support/api#upload) URI, then click **Save**. ![Tosca Add TestingBot URL](https://testingbot.com/assets/support/integrations/tosca/add-url-ca72779d019219c3e3ef0b0400f2b91d5b0572eb04b5266a6f52d08fe440d7af.webp) 5. Now we'll need to add the TestingBot key and secret, to authenticate with the TestingBot grid. Click **Advanced Configuration** , then **Add Capabilities Set** and click the **Add capability** button to add both **key** and **secret** capabilities, with their values being your actual TestingBot key and secret, obtained from the member area. 6. In the **Establishing connection** input, click **Scan**. After a while, you will see a success message. ![Tosca Connection Established](https://testingbot.com/assets/support/integrations/tosca/connection-established-a5f4310dca23e4b8f237a91e65f81e9c0dcdaf79a66286e3f5d98ce30ba7da35.webp) You now have access to a live view of the device running on TestingBot. You can interact with the device by using the buttons. ![Tosca TestingBot Live View](https://testingbot.com/assets/support/integrations/tosca/live-view-7b52a4fd92175f3ef69e5d1d8afb88ec1e3e10f84631cf8299821501da8411d4.webp) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/zebrunner # Zebrunner Zebrunner offers test management with smart analysis of test results. Run and view tests from the Zebrunner UI on TestingBot through the [Zebrunner and TestingBot integration](https://zebrunner.com/documentation/integrations/testingbot). The Zebrunner - TestingBot integration provides Zebrunner users the following features: - Launch TestingBot automated tests - View test results, including screenshots, logs and a video from the Zebrunner UI - Access to TestingBot credentials ## Configuration To configure this integration, please perform the following steps: 1. Log in to your [TestingBot member dashboard](https://testingbot.com/members) and copy your **TestingBot Key** and **TestingBot Secret**. 2. Log in to Zebrunner, select a project and click **Integrations**. 3. Select the TestingBot integration, and enter the following details: 4. Click **Save** to save the configuration. It is now possible to launch tests on the TestingBot browser grid. ## Run Test To run a test, go to the project and open the **Launcher** view where you can select the TestingBot integration. You can choose a browser/version/OS combination with the dropdown menus. ![Zebrunner and TestingBot](https://testingbot.com/assets/support/zebrunner/zebrunner-demo-6b9a40a242a45528d8f8d167e5eb93561998b62e515d5b4b8b00edbb30cfa5c6.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/webhooks # Webhooks Integration Add the TestingBot Webhooks integration to receive Webhook URL requests with the status of your tests. Rather than polling for updates through the [TestingBot API](https://testingbot.com/support/api), you can instantly receive updates as they become available. ## Configure To configure a Webhook, please log in to the TestingBot member area, then navigate to the [Integrations Page](https://testingbot.com/members/integrations). - Click the **Webhooks** integration - Click the **Add Webhook** button - Enter your URL which will receive the POST requests (in JSON format) - Select whether you want to receive a Webhook for all tests, or only for the failed tests - Click **Save** to complete the configuration. - Your webhook now appears in the overview page, where you can edit or delete the webhook. Once these steps are completed, you will start receiving Webhook requests to the URL you specified. Requests may come with a delay of up to 120 seconds. If for some reason your Webhook endpoint does not respond with a 2xx response code, we will automatically retry the request, up to 5 times. ## Webhook Payload Your Webhook URL will receive a POST request in JSON format with the following payload: Data Field | Format | Description || `id` | STRING | The unique id of the test. Usually this will be a WebDriver SessionId, or Playwright/Puppeteer unique id. | | `creation_time` | DATETIME | The date-time value, in `YYYY-MM-DDTHH:mm:ssZ` format, at which the test launched. | | `completion_time` | DATETIME | The date-time value, in `YYYY-MM-DDTHH:mm:ssZ` format, at which the test was completed. | | `user_id` | STRING | The id of the user who launched the test. | | `team_id` | STRING | The id of the team for which this test was run. | | `status` | ENUM | The status of the test, which can be one of the following values: - `PASSED` - `FAILED` - `UNKNOWN` | | `name` | STRING | The name of the test, if it was passed through the [capabilities](https://testingbot.com/support/web-automate/selenium/test-options#name) or [set by API](https://testingbot.com/support/api#updatetest). | | `browser_name` | STRING | The name of the browser on which this test ran. In case of a mobile app test, this might be `NULL`. | | `device_name` | STRING | The name of the device on which this test ran. Might be `NULL` when this test ran on a Desktop environment. | | `browser_version` | STRING | The version of the browser on which this test ran. In case of a mobile app test, this might be `NULL` or the device's version. | | `platform` | STRING | The OS on which this test ran. | | `duration_sec` | INTEGER | How long the test took to complete, the duration is in seconds. | | `build` | STRING | The build this test belongs to, if it was passed through the [capabilities](https://testingbot.com/support/web-automate/selenium/test-options#build) or [set by API](https://testingbot.com/support/api#updatetest). | | `tags` | ARRAY | Array of strings that were added for this test, if it was passed through the [capabilities](https://testingbot.com/support/web-automate/selenium/test-options) or [set by API](https://testingbot.com/support/api#updatetest). | | `errors` | ARRAY | Array of error objects that were reported for this test. Empty if no errors were reported. The error objects are structured like this: errors = [ { message: "The error message", test_name: "The name of the sub test, if any. For example a Flow name when testing with Maestro" } ] | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd # Continuous Integration Continuous Integration makes it easy to run tests at a given interval, after committing new code, before deploying changes, etc. There are various providers offering Continuous Integration, both cloud-based services and do-it-yourself services. If you're looking to host your own CI, here are some options: [Jenkins](https://jenkins.io/), [Bamboo](https://www.atlassian.com/software/bamboo) and [TeamCity](https://www.jetbrains.com/teamcity/). ## Example CI Integrations with TestingBot Please follow a tutorial below to connect your tests with TestingBot and your CI of choice: - [Azure Devops (VSTS)](https://testingbot.com/support/integrations/ci-cd/azure) - [Bamboo](https://testingbot.com/support/integrations/ci-cd/bamboo) - [Bitbucket Pipelines](https://testingbot.com/support/integrations/ci-cd/bitbucket) - [Bitrise](https://testingbot.com/support/integrations/ci-cd/bitrise) - [Circle CI](https://testingbot.com/support/integrations/ci-cd/circleci) - [GitHub Actions](https://testingbot.com/support/integrations/ci-cd/github-actions) - [GitLab CI](https://testingbot.com/support/integrations/ci-cd/gitlab) - [Jenkins CI](https://testingbot.com/support/integrations/ci-cd/jenkins) - [TeamCity CI](https://testingbot.com/support/integrations/ci-cd/teamcity) - [Travis CI](https://testingbot.com/support/integrations/ci-cd/travis-ci) ## CI Plugins We also provide a Jenkins plugin that makes integrating your tests with TestingBot on Jenkins very easy. It allows you to view your test results straight from inside Jenkins. See [how to install this Jenkins plugin](https://testingbot.com/support/integrations/ci-cd/jenkins-plugin). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/azure # Azure Devops (VSTS) Azure Devops (formerly Team Foundation Server and Visual Studio Team System) is a CI service owned by Microsoft. TestingBot has a [Marketplace Extension](https://marketplace.visualstudio.com/items?itemName=testingbot.comingbot-tasks) that offers some features to better integrate TestingBot with Azure Devops: - Set TestingBot environment variables (`TB_KEY` and `TB_SECRET`) to be used by your tests. - Embed overview of your tests in Azure Devops. - Start/Stop [TestingBot Tunnel](https://testingbot.com/support/tunnel) for specific builds. ## Installing Azure Pipelines extension 1. Make sure you are logged in to Azure Devops. Then please go to the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=testingbot.comingbot-tasks) and download the TestingBot extension. 2. Click on **Get it free** to install the extension. 3. Using the **Select an Azure DevOps organization** drop-down menu, choose the organization and click **install**. ## Configure the pipeline Now that the TestingBot extension has been installed, you'll need to configure the **Service Connection**. - Go to **Project Settings** and select **Service connections**. - Click **New Service Connection**. You can now add the **TestingBot credentials**. ![service connection](https://testingbot.com/assets/support/azure/serviceconnection-28f4f9d1e45db5b5e792de642feec247ddbaab1b80b4e26da2d3118cd8c27d60.png) ![new service connection](https://testingbot.com/assets/support/azure/newserviceconnection-fd4a7a4304e4de7459212127db1320f8c6a2561a1768113d7cb4ddc7bbd6c2de.png) - Add a **Service connection name** and click **Save**. Now that we've set up the Service Connection, we can go ahead and add the custom TestingBot task to the `azure-pipelines.yml` file. To do this, you can edit the file in your favorite editor, or through the YAML editor on Azure Devops. ### TestingBot Task In the `steps` block, you can now add the TBMain task, either via the Task menu in the Azure Devops page or by editing the file: - task: TBMain@0 inputs: connectedServiceName: '{your service-connection-name}' ![TestingBot task](https://testingbot.com/assets/support/azure/task-df76373dd1b555f4fbf1366266775bb4bea3cbc49e8c33e8b1c3a931656eb327.png) ![TestingBot credentials](https://testingbot.com/assets/support/azure/credentials-f7f03c7c8483411685fcc4cdd91907b104f84cbd7ef83a12f931eeaed9d37813.png) ## Viewing Test Results The extension allows you to view test results from Azure. To enable this, make sure you followed the previous steps and modify your existing test or test suite to send an extra capability to TestingBot: `build`. The extension makes the following environment variables available for your test cases: - `TB_KEY` - `TB_SECRET` - `TB_BUILD_NAME` The `TB_BUILD_NAME` environment variable needs to be passed as a `build` capability, for example: DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, browser); capabilities.setCapability(CapabilityType.VERSION, version); capabilities.setCapability(CapabilityType.PLATFORM, os); capabilities.setCapability("name", methodName); // this capability below will make sure the reporting works capabilities.setCapability("build", System.getenv("TB_BUILD_NAME")); webDriver.set(new RemoteWebDriver( new URL("https://" + System.getenv("TB_KEY") + ":" + System.getenv("TB_SECRET") + "@hub.testingbot.com/wd/hub"), capabilities)); It is **important** to pass the `TB_BUILD_NAME` environment variable as a `build` capability for the reporting to work. Once the build is complete, you will see a **TestingBot** tab. This will show an overview of the tests for this build. ![TestingBot embed test results](https://testingbot.com/assets/support/azure/embed-5c5a048690d9148927bbbb882d02f5163b343531236578afd29eeaeb736bb234.png) ## Enable TestingBot Tunnel [TestingBot Tunnel](https://testingbot.com/support/tunnel) allows you to run tests against web applications hosted on private, staging or development machines. To enable the TestingBot Tunnel in Azure, make sure the **TestingBot Tunnel checkbox** is checked. ![TestingBot enable tunnel](https://testingbot.com/assets/support/azure/enabletunnel-34e07bb4d8b6335bd9218f2b57ab9a6a51fa7f75212be0ff385942f38a2397f3.png) To use the Tunnel with your test, make sure to edit your test to use the Tunnel IP (`localhost:4445`): DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability(CapabilityType.BROWSER_NAME, browser); capabilities.setCapability(CapabilityType.VERSION, version); capabilities.setCapability(CapabilityType.PLATFORM, os); capabilities.setCapability("name", methodName); // this capability below will make sure the reporting works capabilities.setCapability("build", System.getenv("TB_BUILD_NAME")); webDriver.set(new RemoteWebDriver( new URL("https://" + System.getenv("TB_KEY") + ":" + System.getenv("TB_SECRET") + "@localhost:4445/wd/hub"), capabilities)); ### Stop Tunnel It's important to close the tunnel at the end of your test. To do this, please add the **Stop TestingBot Tunnel task** in your `azure-pipelines.yml` file. Make sure to add the `TBStopTunnel@0` after your other tasks. ![TestingBot stop tunnel](https://testingbot.com/assets/support/azure/stoptunnel-5255e360c29c8671ec9dbcbf6dfa1a627b998c73e71f631efb162bdbcb2c27ff.png) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/bamboo # Bamboo Plugin TestingBot has created a plugin to be used with Atlassian's Bamboo CI: [TestingBot Plugin for Bamboo](https://marketplace.atlassian.com/apps/1221640/testingbot-plugin-for-bamboo) This plugin integrates TestingBot in Bamboo, features include: - Configure builds to use TestingBot: add environment variables with your TestingBot credentials - See a video, logs and screenshots of each test in Bamboo - Optionally start/stop [TestingBot Tunnel](https://testingbot.com/support/tunnel) for each build. ## Installation via Website To get started, go to the [Atlassian MarketPlace](https://marketplace.atlassian.com/apps/1221640/testingbot-plugin-for-bamboo), and click the **Get it now** button for the **TestingBot Plugin for Bamboo**. This will download a `.jar` file that you can use. ## Installation from inside Bamboo - Log into your Bamboo instance as an admin. - Click the admin dropdown and choose **Add-ons**. - Click **Find new apps** or **Find new add-ons** from the left-hand side of the page. - Locate **TestingBot Plugin for Bamboo** via search. - Click **Install** to download and install your app. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/bitbucket # Bitbucket Pipelines WebDriver Testing Bitbucket Pipelines makes it very easy to do Continuous Integration. You can configure Bitbucket Pipelines by adding a `bitbucket-pipelines.yml` file to the root of your repository. See our full [Bitbucket Pipelines example](https://bitbucket.org/testingbot/bitbucket-pipelines) to see how easy it is to use TestingBot with Bitbucket Pipelines. ## Configuration 1. Go to your Bitbucket repository settings and add the following environment variables: **TB\_KEY** : Your TestingBot Key **TB\_SECRET** : Your TestingBot Secret 2. Configure **bitbucket-pipelines.yml** with the example configuration below: image: ruby:2.1 pipelines: default: - step: script: - apt-get update - apt-get install unzip - bundle install - bundle exec rackup -p 8001 > /dev/null & - ./run_local.bash - bundle exec rspec spec/welcome.rb - pkill -9 rackup The `run_local.bash` script will download our [TestingBot Tunnel](https://testingbot.com/support/tunnel) #!/bin/bash -e wget https://testingbot.com/tunnel/testingbot-tunnel.jar java -jar testingbot-tunnel.jar ${TB_KEY} ${TB_SECRET} > /dev/null & sleep 10 3. Read the Bitbucket environment variables in your test. For example, with RSpec: require 'selenium-webdriver' require 'rspec' RSpec.configure do |config| config.color_enabled = true end describe "The welcome demo" do before(:all) do testingbot_key = ENV['TB_KEY'] testingbot_secret = ENV['TB_SECRET'] caps = Selenium::WebDriver::Remote::Capabilities.new caps['platform'] = 'WINDOWS' caps['version'] = 'latest' caps['browserName'] = 'chrome' caps['build'] = 'Bitbucket Pipeline' caps['name'] = 'Bitbucket Pipeline' @driver = Selenium::WebDriver.for(:remote, :url => "https://#{testingbot_key}:#{testingbot_secret}@hub.testingbot.com/wd/hub", :desired_capabilities => caps) end after(:all) do @driver.quit end it "should have a welcome page" do username = 'Test User' @driver.get 'http://localhost:8001' @driver.find_element(:name ,'name').send_keys username @driver.find_element(:css, "input[type='submit']").click actual_text = @driver.find_element(:css, "h2").text actual_text.should == "Welcome, #{username}" end end Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/bitrise # Bitrise Upload App Action TestingBot has developed a [TestingBot App Upload](https://www.bitrise.io/integrations/steps/testingbot-upload-app) integration which allows you to upload an `APK` or `IPA` file from Bitrise to TestingBot. Once uploaded, you can run automated mobile app tests against the mobile app via TestingBot's physical devices and simulators/emulators. This step is valid for the following project types: - ios - android - xamarin - react-native - cordova - ionic - flutter ## Required Inputs The following input values are required for this step: ### apk\_ipa\_filepath The app file you want to upload, usually this comes from the environment variable `$BITRISE_APK_PATH` or `$BITRISE_IPA_PATH`. ### testingbot\_key The TestingBot key associated to your account, available in our member dashboard. ### testingbot\_secret The TestingBot secret associated to your account, available in our member dashboard. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/circleci # Circle CI Automated Testing Circle CI is a continuous integration service in the cloud. It is very easy to use the TestingBot Selenium grid together with Circle CI. Below are the steps to run your Selenium tests via Circle CI, once the tests are up and running you can even display a TestingBot Status badge showcasing your Selenium tests status. ## Get Circle CI up and running Sign up at [Circle CI](https://circleci.com) and connect your project with Circle CI. We recommend setting up [environment variables](https://circleci.com/docs/guides/security/set-environment-variable/) on the project settings page of CircleCI. You can set up the `TB_KEY` and `TB_SECRET` variables there, so that they are not publicly visible. **Example circle.yml file:** version: 2.1 orbs: ruby: circleci/ruby@1.4.0 node: circleci/node@2 jobs: test: parallelism: 3 # depends on how many concurrent sessions your TestingBot subscription has docker: - image: cimg/ruby:2.7-node auth: username: mydockerhub-user password: $DOCKERHUB_PASSWORD # context / project UI env-var reference environment: SELENIUM_HOST: hub.testingbot.com SELENIUM_PORT: 80 TB_AUTOMATE_BUILD: "build No. $CIRCLE_BUILD_NUM for circleCI" SELENIUM_PLATFORM: WINDOWS SELENIUM_BROWSER: Chrome SELENIUM_BROWSER_VERSION: "latest" steps: - checkout - ruby/install: version: '2.7' - ruby/install-deps - bundle exec cucumber workflows: version: 2 test: jobs: - test: You can now use the environment variables, defined above and on CircleCI, in your code: require 'selenium/webdriver' url = "http://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@hub.testingbot.com/wd/hub" capabilities = Selenium::WebDriver::Remote::Capabilities.new capabilities['build'] = ENV['TB_AUTOMATE_BUILD'] if ENV['TB_AUTOMATE_BUILD'] capabilities['platform'] = ENV['SELENIUM_PLATFORM'] || 'ANY' capabilities['browserName'] = ENV['SELENIUM_BROWSER'] || 'chrome' capabilities['version'] = ENV['SELENIUM_BROWSER_VERSION'] if ENV['SELENIUM_BROWSER_VERSION'] browser = Selenium::WebDriver.for(:remote, :url => url, :desired_capabilities => capabilities) Before do |scenario| @browser = browser end at_exit do browser.quit end Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/github-actions # TestingBot GitHub Action This guide will help you integrate the TestingBot GitHub Action workflow in your project. The TestingBot GitHub action provides an action to integrate the [TestingBot Tunnel](https://testingbot.com/support/tunnel) in your tests. The TestingBot Tunnel is used to route all test traffic between your web application and the TestingBot browser/device cloud. The GitHub action will also save the [test-artifacts](https://testingbot.com#artifacts) for you, so that you can later see the meta-data generated by the test. ## GitHub Secrets To get started, you'll need to configure 2 secrets in your GitHub repository. These 2 secrets are `TB_KEY` (your TestingBot Key) and `TB_SECRET` (TestingBot secret) which can be obtained from the TestingBot member area. In your GitHub repository, go to **Settings** and find the **Secrets** option in the left-hand pane. Add both the `TB_KEY` and `TB_SECRET` as **Repository Secrets** : ![GitHub Secrets](https://testingbot.com/assets/support/github/secrets-5e390bc9c169a9b3e4d247c00606334ada9202d731436d23d7f96c099d0b1829.webp) ## Set up a GitHub workflow Next, we'll create a new GitHub workflow. Create a workflow file `test-workflow.yml` in the `.github/workflows` directory of your GitHub repository. You can find out more about workflow files on the [GitHub documentation pages](https://docs.github.com/en/actions/learn-github-actions#creating-a-workflow-file). In your workflow file, you can indicate [when to run the GitHub Action](https://docs.github.com/en/actions/reference/events-that-trigger-workflows). We recommend doing this on both `push` and `pull_request` for maximum test coverage: name: "TestingBot Test" on: [push, pull_request] jobs: test: runs-on: ubuntu-latest name: Sample Test ... You can specify a `runs-on` parameter, to indicate the OS of the container that should run your test. The most important part is the `steps` section, which we'll cover in the example below. ## Example workflow with TestingBot Let's set up a workflow that will do the following actions: - Checkout the current GitHub repository code - Install dependencies for the project - Run the tests in the repository name: "PR Checks" on: push jobs: test: runs-on: ubuntu-latest name: Action Test steps: - uses: actions/checkout@v1 - uses: testingbot/testingbot-tunnel-action@v1 with: key: ${{ secrets.TB_KEY }} secret: ${{ secrets.TB_SECRET }} tunnelIdentifier: github-action-tunnel - name: "Install Dependencies" run: npm install - name: "Run Test" run: npm run test env: TB_KEY: ${{ secrets.TB_KEY }} TB_SECRET: ${{ secrets.TB_SECRET }} Here we're including the `testingbot/testingbot-tunnel-action` TestingBot GitHub action with a `key`, `secret` and `tunnelIdentifier`. The `tunnelIdentifier` is used to indicate in your tests that a connection should be made to this specific tunnel. ### Example Test For example, let's say your `npm run test` starts a local `http-server` and then runs a `Selenium WebDriver` test: http-server ./test -p 8080 > /dev/null 2>&1 & [Ruby](https://testingbot.com#)[Python](https://testingbot.com#)[PHP](https://testingbot.com#)[Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#) #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "chrome" caps["version"] = "latest" caps["platform"] = :WINDOWS caps["name"] = "GitHub Action Test" caps["tunnel-identifier"] = "github-action-tunnel" client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 120 driver = Selenium::WebDriver.for( :remote, :url => "https://#{ENV['TB_KEY']}:#{ENV['TB_SECRET']}@hub.testingbot.com/wd/hub", :desired_capabilities => caps, :http_client => client) driver.navigate.to "http://localhost:8080" puts driver.title driver.quit import org.openqa.selenium.By; import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.io.File; import java.io.FileWriter; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.net.URL; public class AccessibilityTest { public static final String KEY = System.getenv("TB_KEY"); public static final String SECRET = System.getenv("TB_SECRET"); public static final String URL = "http://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; public static void main(String[] args) throws Exception { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("version", "latest-1"); caps.setCapability("platform", "WIN10"); caps.setCapability("name", "GitHub Action Test"); caps.setCapability("tunnel-identifier", "github-action-tunnel"); WebDriver driver = new RemoteWebDriver(new URL(URL), caps); driver.get("http://localhost:8080"); System.out.println(driver.getTitle()); driver.quit(); } } "WIN10", "browserName"=>"chrome", "version" => "latest", "name" => "GitHub Action Test"), 120000 ); $web_driver->get("http://localhost:8080"); echo $web_driver->getTitle(); $web_driver->quit(); ?> from selenium import webdriver desired_cap = { 'platform': 'WIN10', 'browserName': 'chrome', 'version': 'latest-1', 'name': 'GitHub Action Test' } tbKey = os.environ['TB_KEY'] tbSecret = os.environ['TB_SECRET'] driver = webdriver.Remote( desired_capabilities=desired_cap, command_executor='https://' + tbKey + ':' + tbSecret + '@hub.testingbot.com/wd/hub', ) driver.get("http://localhost:8080") print(driver.title) driver.quit() const webdriver = require('selenium-webdriver'); const fs = require('fs') const testingbotKey = process.env.TB_KEY; const testingbotSecret = process.env.TB_SECRET; const capabilities = { 'browserName': 'firefox', 'platform': 'WIN10', 'version': 'latest', 'client_key': testingbotKey, 'client_secret': testingbotSecret, 'name': 'GitHub Action Test' }; async function runGitHubActionTest () { let driver = new webdriver.Builder() .usingServer('https://' + testingbotKey + ':' + testingbotSecret + '@hub.testingbot.com/wd/hub') .withCapabilities(capabilities) .build(); await driver.get("http://localhost:8080"); const title = await driver.getTitle(); console.log(title) await driver.quit(); } runGitHubActionTest(); using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace SeleniumTest { class Program { static void Main(string[] args) { IWebDriver driver; DesiredCapabilities capability = DesiredCapabilities.Chrome(); capability.SetCapability("key", Environment.GetEnvironmentVariable("TB_KEY")); capability.SetCapability("secret", Environment.GetEnvironmentVariable("TB_SECRET")); capability.SetCapability("version", "latest-1"); driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub/"), capability ); driver.Navigate().GoToUrl("http://localhost:8080"); Console.WriteLine(driver.Title); driver.Quit(); } } } Your test will connect to the local http-server via the TestingBot GitHub Action and print the title of the page. ## Inputs The TestingBot GitHub Action accepts the following inputs: | Input | Description | | --- | --- | | `key` **Required** | Your TestingBot API Key | | `secret` **Required** | Your TestingBot API Secret | | `auth` | Performs Basic Authentication for specific hosts, only works with HTTP. | | `debug` | Enables debug messages. Will output request/response headers. | | `dns` | Use a custom DNS server. For example: 8.8.8.8 | | `doctor` | Perform sanity/health checks to detect possible misconfiguration or problems. | | `fastFailRegexps` | Specify domains you don't want to proxy, comma separated. | | `pac` | Proxy autoconfiguration. Should be a http(s) URL | | `sePort` | The local port your Selenium test should connect to. Default port is 4445 | | `localProxy` | The port to launch the local proxy on (default 8087). | | `proxy` | Specify an upstream proxy: `PROXYHOST:PROXYPORT` | | `proxyCredentials` | Username and password required to access the proxy configured with `proxy`. | | `noCache` | Bypass TestingBot Caching Proxy running on the tunnel VM. | | `noProxy` | Do not start a local proxy (requires user provided proxy server on port 8087). | | `tunnelIdentifier` | Add an identifier to this tunnel connection. In case of multiple tunnels, specify this identifier in your desired capabilities to use this specific tunnel. | | `uploadLogFile` | Should this action [upload the log file](https://testingbot.com#artifacts) generated by the TestingBot Tunnel as an artifact? Default is true. | | `retryTimeout` | How long, in seconds, should the Action wait to retry, if the tunnel fails to start. | ## Artifacts The TestingBot GitHub Action will, by default, upload the logfile generated by the TestingBot tunnel. This allows you to view what happened with the TestingBot Tunnel for each of your Actions. The logfile is saved as an artifact and can be downloaded. ![GitHub Artifact](https://testingbot.com/assets/support/github/artifact-9ec2869f7e562823c0fac8784cbde1a2fc0820830e31410393405b00bed32d49.webp) If you don't want this, you can disable it by setting the input `uploadLogFile: "false"` in your workflow file. ## More Information More information about this is available on the [GitHub Documentation pages](https://docs.github.com/en/actions) and our [TestingBot GitHub Action repository](https://github.com/testingbot/testingbot-tunnel-action). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/gitlab # GitLab CI Automated Testing GitLab CI/CD is a part of GitLab and provides a Continuous Integration system to run automated tests. Below are the steps to run your Selenium tests via GitLab CI, once the tests are up and running you can even display a TestingBot Status badge showcasing your Selenium tests status. ## 1. Get GitLab CI up and running Download [GitLab CI](https://about.gitlab.com/product/continuous-integration/) and set up GitLab CI to your requirements. ## 2. Create a simple Selenium test Add a simple Selenium test to your GitLab project, modify the .gitlab-ci.yml file in your repository to indicate you want to run a Selenium test. Example `.gitlab-ci.yml` file: image: node:latest stages: - Test TestingBot Selenium Test: stage: Test TestingBot before_script: - npm install - npm install selenium-webdriver script: - node sample_test.js Add your `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` environment variables to [GitLab's Variables Page](https://gitlab.com/help/ci/variables/README#variables). var webdriver = require('selenium-webdriver'); async function runSampleTest () { let driver; try { driver = new webdriver.Builder(). withCapabilities({ 'browserName': 'chrome', 'platform': 'WIN10', 'version': 'latest', 'client_key': process.env.TESTINGBOT_KEY, 'client_secret': process.env.TESTINGBOT_SECRET, 'name': (process.env.CI_JOB_ID ? ("GitLab Build " + process.env.CI_JOB_ID) : "Simple Test") }). usingServer("https://" + process.env.TESTINGBOT_KEY + ":" + process.env.TESTINGBOT_SECRET + "@hub.testingbot.com/wd/hub"). build(); await driver.get('https://www.google.com'); var title = await driver.getTitle(); console.log("title is: " + title); } catch (e) { console.log(e); } finally { if (driver) { await driver.quit(); } } } runSampleTest(); Now you're ready to run this first sample test with GitLab CI. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/jenkins # Jenkins Automated Testing Jenkins is a Java-based, open-source continuous integration (CI) system. **We've created a Plugin for Jenkins with lots of features, more information [on this page](https://testingbot.com/support/integrations/ci-cd/jenkins-plugin)** With Jenkins you can run your tests at the frequency you desire. You could for example run your Selenium tests every hour, or after each xx commits to your version control system. You can download Jenkins from [the official Jenkins page](https://www.jenkins.io/). Below you will find a tutorial on how to integrate Jenkins with Selenium. We'll set up a basic example where a simple Selenium test will run on Jenkins and the TestingBot Selenium grid. Once you've followed this setup, you'll be able to run your Selenium tests on our remote server. ## 1. Specify API credentials To identify to our Selenium grid, you need to specify your API Key and Secret. [Download credentials file](https://testingbot.com/members/download) Download the credential file and copy it to your home directory (`~/.testingbot`) on your Jenkins machine. ## 2. Set up a new job ![set up a new Jenkins job](https://testingbot.com/assets/support/jenkins1-8f7d9ba01177533e125222639fb5973b4ac35e8ef80aa6d74861ae1a5189cf63.jpg) Click the "New Job" button from the main Jenkins dashboard. ## 3. Specify job settings ![specify job settings](https://testingbot.com/assets/support/jenkins2-a58ad9ab74051f8533cc2dc776da5f93b0658a4ddfabdcf6d913171baa90531b.jpg) Specify a name for the job and pick the option "Build a free-style software project" in the Jenkins configuration. ## 4. Git settings ![git settings](https://testingbot.com/assets/support/jenkins3-66def661d36ee2352f85e2b118012dc8218d35c3c4ae10f33893e1f94fe0d455.jpg) Pick Git for Source Code Management and enter the repository URL for this demo: `git://github.com/testingbot/Jenkins-Demo.git` This means Jenkins will each time fetch the latest code from our [GitHub repository](https://github.com/testingbot/Jenkins-Demo) and run the tests from that code. ## 5. Build Step ![build step](https://testingbot.com/assets/support/jenkins4-46aebddaca21bc719eac48cf31af25759d8ae064f0c1b9cabe779592a9104239.jpg) In the next step we'll specify how Jenkins needs to build or test the project. Our test project contains a `build.xml`, so we can use Ant to build the project. Pick Ant from the build menu. ![ant](https://testingbot.com/assets/support/jenkins5-46d311acc4904e5ed1641ad47bb50f5673e00ffb3f2afd4ff84e8ab14138025c.jpg) The Ant target is: **test** ## 6. Publish JUnit results ![publish junit results](https://testingbot.com/assets/support/jenkins6-fe05a0504876a08639a9d88ee66743945d37697bea0534cd414dc0a89935b03c.jpg) Make sure to publish the JUnit test results report to `test-reports/*.xml` ## 7. Run Jenkins job ![run Jenkins job](https://testingbot.com/assets/support/jenkins7-7601d596fa84f63f2ddd7ebb3a6a7d52a54eecc57941312a73e196d134c53b4c.jpg) You are now ready to run your first Jenkins job. Click the **Build Now** button. Results should be available in a minute. ## 8. Jenkins test results ![Jenkins Test Results](https://testingbot.com/assets/support/jenkins8-d66b10e0f91654c8036b89284e3ba60735631cf78d4ce5c346a19a737674ba89.jpg) Now you can see the test results in Jenkins. The blue circle means the test was successful! You can also see the status of your tests in the console output of the Jenkins job. You will now see your test and its screenshots/video in our TestingBot.com member area. ## 9. TestingBot Integration ![Jenkins TestingBot integration](https://testingbot.com/assets/support/demo9-8c828e01802d1c2f871dc5ccfdd732256a0cd192a157f3240a8a4457769c9e6d.jpg) With the TestingBot [Jenkins plugin](https://testingbot.com/support/integrations/ci-cd/jenkins-plugin) you can easily see a video/screenshots of your test from inside Jenkins. Once the plugin is installed, it will report the test success/failures to TestingBot and embed the TestingBot test report inside your Jenkins installation. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/jenkins-plugin # Jenkins Plugin We maintain a plugin for Jenkins which integrates TestingBot's services inside Jenkins. - Run your tests through [our secure tunnel](https://testingbot.com/support/tunnel) between your staging environment (Jenkins) and our grid. - See a video and screenshots of every test from inside Jenkins. - Displays a detailed list of Selenium steps, metadata, log files and errors. - Report test success results to TestingBot. - Supports Jenkins Credentials and Pipeline (Jenkinsfile). The [plugin's Wiki on Jenkin's website](https://plugins.jenkins.io/testingbot) provides the information required to install, configure and use our plugin. ### 1. Installation Click the "Manage Jenkins" link from the Jenkins homepage. ![install Jenkins plugin](https://testingbot.com/assets/support/jenkinsplugin-3cd22c1a95b26c5e04b9f65a52636ca271bbd14521f0abb81b9682c3343a4741.jpg) ### 2. Choose Manage Plugins ![manage Jenkins plugins](https://testingbot.com/assets/support/jenkinsplugin1-74d902c8d16c27b194b8ab1afe469d59d3071078b71144d63bf8ec4628a90e31.jpg) Click the "Manage Plugins" button. ### 3. Install our plugin ![install the TestingBot + Jenkins plugin](https://testingbot.com/assets/support/jenkinsplugin2-2961e5fea5380a7995c032a60e30bfcf2d4cdd9e1b56232df5be07c949db9dd6.jpg) Click "Available" and look for our TestingBot plugin. Check the box next to our plugin and click "Install without restart" ### 4. Configuration ![configure Jenkins plugin](https://testingbot.com/assets/support/jenkinsplugin3-dc6c0c568e45aacc06650c98605368804e5c9858c90e0ed86819cde365957418.png) Go to **Manage Jenkins** \> **Configure System** , scroll down to where you can enter the TestingBot credentials. Add your API key and secret, which you can obtain from our [member area](https://testingbot.com/members). ### 5. Setting up the Build Environment ![Jenkins build environment](https://testingbot.com/assets/support/buildenv-5da06b9535dace7d5266d15e54fe0a80b1b2409bd07603bdc1a81ad9e8e33363.png) In the Build Environment section, enable the 'TestingBot' option. The API key you entered previously should be visible there, together with an option to use the TestingBot Tunnel during your build. ### 6. Embedded TestingBot Reports ![embed test report in Jenkins](https://testingbot.com/assets/support/postbuild-292fc5655cdd2fe77fa202857b52ffdcd1b20f9462b6cc9521f4959a0571f61a.png) The plugin will parse the JUnit test result files in the post-build step to associate test results with TestingBot jobs. Please make sure that the JUnit plugin is installed. Click on `Add post-build action` in `Post-build Actions`. Make sure you enable `Publish JUnit test result report` and point to the correct test report files (for example `test-reports/*.xml`). ![Jenkins publisher](https://testingbot.com/assets/support/publisher-c95f8ae49d89f86159b5e4204d8b8dcaece743d797c27c6359f9af9c29d90db1.png) ### 7. Results ![test results in Jenkins](https://testingbot.com/assets/support/summary-16a0622a0da9ceba7537f719cddd789f06ff01b1117c7f00b6ae320f77a65e97.png) **Important:** To see the result (logs/video/screenshots) of your test, **your test needs to output "TestingBotSessionID=xxx"** If you're using JUnit reporting, the `TestingBotSessionID=xxx` needs to be in a \xxx\ tag in the JUnit report XML file. Our plugin will use this sessionID (the Selenium WebDriver sessionId) to show the correct test details for your test. For more information, see our [JUnit WebDriver example](https://github.com/testingbot/Jenkins-Demo/blob/master/test/SmokeTest.java#L53). ## Jenkins Pipeline The plugin provides support for Jenkins' Pipelines (Jenkinsfile). Currently the plugin offers these commands: - `testingbot(String credentialId)` - `testingbotTunnel(credentialsId: '', options: ' -d -a')` - `testingbotPublisher()` The `testingbot()` command requires a `credentialId)` which is the Id you can find on the Jenkins Credentials page, the unique Id connected to the TestingBot API key and Secret you entered previously. This command will set environment variables which you can use in your test, including `TB_KEY)` and `TB_SECRET)`. The `testingbotTunnel()` command requires both a `credentialId` and `options`. The options are the options you can specify with the TestingBot Tunnel. This will start the tunnel before your job runs. Once the job finishes, the tunnel will be shutdown. `testingbotPublisher()` will try to read the JUnit report files and show the test results from TestingBot. An Example: pipeline { agent any tools { // Install the Maven version configured as "M3" and add it to the path. maven "M3" ant "ant" } stages { stage('Build') { steps { // Get some code from a GitHub repository git 'https://github.com/testingbot/Jenkins-Demo.git' testingbot('251ca561abdfewf285') { testingbotTunnel(credentialsId: '251ca561abdfewf285', options: '-d') { sh "ant test" } } } post { success { junit 'test-reports/*.xml' } always { testingbotPublisher() } } } } } Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/teamcity # TeamCity Automated Testing [TeamCity](https://www.jetbrains.com/teamcity/) is a Java-based build management/CI system created by Jetbrains. ## TeamCity Plugin We've created a plugin which offers integration with our TestingBot.com services. Below is a list of features this plugin offers: - Add a tab where we show the lists of tests for the current build. The overview shows a list of tests with their **passed/failed state** , together with the **browser they ran on**. - View **logs** (Selenium, Chrome, Firefox, Safari logs) and a **recorded video** together with **screenshots** of every test, straight from inside TeamCity. - Option to start/stop a [TestingBot Tunnel](https://testingbot.com/support/tunnel) automatically before and after every build run. - Predefined environment variables with your TestingBot `key` and `secret`. ## 1. Install the Plugin Go to **Server Administration** and click **Plugins List** ![TeamCity integration](https://testingbot.com/assets/support/teamcity/1-74db237d6656583ac4c1636cd3b186221390986e5c0f62820ab68d962c8fa50d.png) ## 2. Upload Plugin Click on **upload plugin zip** and upload our TestingBot plugin. Or download the plugin from the [TeamCity plugin page](https://plugins.jetbrains.com/plugin/10283-testingbot/). ![TeamCity integration](https://testingbot.com/assets/support/teamcity/2-233fe680aeede14e5c111bd2a4e69a51015b6a26ff9bb718ae80e6467ceba181.png) ## 3. Restart TeamCity Restart TeamCity to see the TestingBot plugin in the plugin list. ## Configuring a Project Now that the plugin is installed, we can use the TestingBot plugin in a TeamCity project. 1. Click on **Build Features** 2. Click **Add build feature** and select **TestingBot** from the list. ![TeamCity integration](https://testingbot.com/assets/support/teamcity/3-0295aa78a57aa5f0fdd0f785bede96f85e20ee56433f92b26a3e794cfa4b6b14.png) ## 3. Credentials Add your TestingBot **Key** and **Secret** , which you can obtain from the member dashboard. ![TeamCity integration](https://testingbot.com/assets/support/teamcity/4-02af8afa78638a7d22f378c873ae3c52f7914574ca3bc15a6c314da54cfd12aa.png) ## 4. Test Overview in TestingBot Tab You can now see an overview of your Selenium tests in the **TestingBot tab**. ![TeamCity integration](https://testingbot.com/assets/support/teamcity/7-bce3812eec0264d98a1262bca33cdc40d72a9870d51ef5b66e7ccb27f98dddd3.png) ## 5. Test Details Click a test to see a **video recording** , **screenshots** and **logs** for the test. ![TeamCity integration](https://testingbot.com/assets/support/teamcity/8-9b9cef361d30b29b05fe23985a96cf93ab46ef1450e022788ea4a62a22f605b2.png) ## 6. Configuring Tests The plugin will automatically set the following **Environment Variables** , which you can use in your tests: - `TB_KEY` : Your TestingBot key, available in our member area. - `TB_SECRET` : Your TestingBot secret, available in our member area. **Important!** It is important to output `TestingBotSessionID={webdriver-session-id}` for every test to stdout. The plugin will parse the output looking for these ids. An example on how to do this with Java: System.out.println("TestingBotSessionID=" + (((RemoteWebDriver) driver).getSessionId()).toString()); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/integrations/ci-cd/travis-ci # Travis CI Automated Testing Travis CI is a continuous integration service which you can easily use to test your GitHub projects. It is very easy to use the TestingBot Selenium grid together with Travis CI. Below are the steps to run your Selenium tests via Travis CI, once the tests are up and running you can even display a TestingBot Status badge showcasing your Selenium tests status. ## 1. Get Travis CI up and running Sign up at [Travis CI](https://travis-ci.org/) and connect your GitHub project with Travis CI. You can find information on how to do this at the Travis CI [help section](https://docs.travis-ci.com/). ## 2. Create a simple Selenium test Add a simple Selenium test to your GitHub project, modify the `.travis.yml` file in your repository to indicate you want to run a Selenium test. Example `.travis.yml` file: language: node_js node_js: - 0.8 env: - [ {secure: "akuE0dld1Ke9mahjUUrQhUZRYWasdfewfwefewfZlbvOx\nqaPybirPGsDmImvcktaAkjLxpePd0V1+ak+4dws7dTrFfEsdvsdsdvsdvds2\nud1q5oGOzEqfiRGxY/fJHLWlaQ609Bsdfdsfds2VeY1Z/V7N9iQ="}, {secure: "JGfkAfr/SOlzV+NpgNi3fxP4F2usdfdsveGAppugHj1IxhoyjY\nOp07x4p1hdIfWVF03RqUrPNXkl72+yh53pv2fUzsdfsd3434GRjGy6J6\notuA/N+xs0+TP2ENlCmDauwO32Okfojvj7CgvsdfdsfRyaFzIGWPdw="} ] script: - "node tests/examples/*.js" The two secure lines in the above example are your TestingBot key and secret, used to run a test on our Grid. To generate these 2 lines, you need to install the Travis CI gem and run these commands with your own key and secret: travis encrypt username/projectname TESTINGBOT_KEY=my_key travis encrypt username/projectname TESTINGBOT_SECRET=my_secret Now you can use the encrypted `TESTINGBOT_KEY` and `TESTINGBOT_SECRET` environment variables in your tests. Below is a NodeJS example: npm install -g selenium-webdriver var webdriver = require('selenium-webdriver'); async function runSampleTest () { let driver; try { driver = new webdriver.Builder(). withCapabilities({ 'browserName': 'chrome', 'platform': 'WIN10', 'version': 'latest', 'client_key': process.env.TESTINGBOT_KEY, 'client_secret': process.env.TESTINGBOT_SECRET, 'name': (process.env.CI_JOB_ID ? ("GitLab Build " + process.env.CI_JOB_ID) : "Simple Test") }). usingServer("https://" + process.env.TESTINGBOT_KEY + ":" + process.env.TESTINGBOT_SECRET + "@hub.testingbot.com/wd/hub"). build(); await driver.get('https://www.google.com'); var title = await driver.getTitle(); console.log("title is: " + title); } catch (e) { console.log(e); } finally { if (driver) { await driver.quit(); } } } runSampleTest(); Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/accessibility # Accessibility testing Automated Accessibility Testing (A11y) allows you to test if your product follows the Web Content Accessibility Guidelines (WCAG) rules and other guidelines, to ensure your product is accessible to all types of users. TestingBot offers [website accessibility testing](https://testingbot.com/support/accessibility/web), which can be directly integrated in your tests. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/accessibility/web # Accessibility Web Testing Automated Accessibility Testing (A11y) allows you to test if your website follows the Web Content Accessibility Guidelines (WCAG) rules and other guidelines, to ensure your website is accessible to all types of users. Please pick a test automation framework to see documentation on how to perform accessibility testing. [![Selenium](https://testingbot.com/assets/integrations/selenium-1403d7bf83f64f56f05cea3fe50ae45bc3025d5a2433b7b05d2b199fec753cf6.svg)Selenium Accessibility Testing](https://testingbot.com/support/accessibility/web/selenium) ## Accessibility ruleset TestingBot uses multiple rules to check for accessibility violations. To see an overview of these rules, please consult the [rules for automatic accessibility checks](https://testingbot.com/support/accessibility/web/rules). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/accessibility/web/scheduled # Accessibility Testing Scheduler Web accessibility is a key part of building inclusive applications—but manually testing for WCAG compliance is often tedious, time-consuming, and easy to overlook in fast-paced development cycles. To streamline this process, TestingBot introduces the Accessibility Scheduler: a developer-friendly tool that automates accessibility scans across your URLs. It runs scheduled checks, highlights WCAG violations and generates detailed reports, which will help you catch issues early. With support for **one-time and recurring scans** , this feature reduces manual QA effort and keeps your workflow efficient. It also helps you prepare for upcoming regulations like the **European Accessibility Act** , by ensuring your app meets legal accessibility standards with minimal friction. ## Key Features - **Automated Scheduling:** Configure one-time or recurring accessibility scans with ease. - **WCAG Compliance:** Validate against WCAG levels to ensure your site meets accessibility standards. - **Support for Local and Authenticated Pages:** Run scans in local or staging environments using the [TestingBot Tunnel](https://testingbot.com/support/tunnel). ## Get started ### 1. Add URL To get started, you need to create a new accessibility test. You can do this by going to the [Accessibility Tests](https://testingbot.com/members/accessibility) page and entering your URL in the form. ![Add Accessibility Test](https://testingbot.com/assets/support/accessibility/add_test-7ce020dcfb0d5e76aef0252e9455d5493f5d1c7847bb05fb61dbdd5b89e3b4d5.jpg) ### 2. Schedule Test You will end up on the edit page, where you can specify how frequently you want to run the test. Choose to schedule the test to run once or at regular intervals (daily, weekly, monthly or at a custom interval). ![Schedule Accessibility Test](https://testingbot.com/assets/support/accessibility/schedule-6ddb7ab66592eef9a7aa135d6af9eea58ecf91a6845a08fc1380d8600c3ae568.jpg) ### 3. Alert When a scheduled accessibility test fails, you can choose to be alerted through email, webhook or SMS text message. ![Accessibility Test Alerts](https://testingbot.com/assets/support/accessibility/alert-3a12ae9d85c28bc590319338b0af86b34a2b0d7020c96ada476171ec366a5096.jpg) ## Results The result page will display the results of the test, including the number of violations found, the rules that were violated and the severity of each violation. You can also view the details of each violation, including the affected elements and the recommended fixes. ![Accessibility Test Results](https://testingbot.com/assets/support/accessibility/results-b40abc1b0648a65423db921a65f17c193a3692225a01cba86ce5979021e08abb.jpg) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/accessibility/web/selenium # Accessibility testing Automated Accessibility Testing (A11y) allows you to test if your website follows the Web Content Accessibility Guidelines (WCAG) rules and other guidelines, to ensure your website is accessible to all types of users. ## Example The following example will start a browser in the TestingBot browser grid, navigate to a website and call the custom `tb:accessibility` command to fetch the accessibility results. We will then retrieve the results from the accessibility test from inside our automated test. The results will be saved in a JSON file for inspection. [Java](https://testingbot.com#)[NodeJS](https://testingbot.com#)[C#](https://testingbot.com#)[Python](https://testingbot.com#)[Ruby](https://testingbot.com#)[PHP](https://testingbot.com#) #!/usr/bin/env ruby require 'rubygems' require 'selenium-webdriver' caps = Selenium::WebDriver::Remote::Capabilities.new caps["browserName"] = "chrome" caps["version"] = "latest" caps["platform"] = :WINDOWS caps["name"] = "Accessibility Test" client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = 120 driver = Selenium::WebDriver.for( :remote, :url => "https://API_KEY:API_SECRET@hub.testingbot.com/wd/hub", :desired_capabilities => caps, :http_client => client) driver.navigate.to "https://testingbot.com" result = driver.execute_script('tb:accessibility') file = open("path/to/report.json", "w") file.write(result) file.close() driver.quit import org.openqa.selenium.*; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import java.io.FileWriter; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; public class AccessibilityTest { public static final String KEY = "KEY"; public static final String SECRET = "SECRET"; public static final String REMOTE_URL = "https://" + KEY + ":" + SECRET + "@hub.testingbot.com/wd/hub"; public static void main(String[] args) { WebDriver driver = null; try { DesiredCapabilities caps = new DesiredCapabilities(); caps.setCapability("browserName", "chrome"); caps.setCapability("version", "latest-1"); caps.setCapability("platform", "WIN10"); caps.setCapability("name", "Accessibility Test"); driver = new RemoteWebDriver(new URL(REMOTE_URL), caps); driver.get("https://testingbot.com"); JavascriptExecutor js = (JavascriptExecutor) driver; String result = (String) js.executeScript("tb:accessibility"); Path outputPath = Files.createTempFile("accessibility-report", ".json"); try (FileWriter writer = new FileWriter(outputPath.toFile())) { writer.write(result); System.out.println("Accessibility report saved to: " + outputPath.toAbsolutePath()); } } catch (Exception e) { e.printStackTrace(); } finally { if (driver != null) { driver.quit(); } } } } "WIN10", "browserName"=>"chrome", "version" => "latest", "name" => "Accessibility Test"), 120000 ); $web_driver->get("https://testingbot.com"); $result = $web_driver->executeScript('tb:accessibility'); $file = fopen("path/to/report.json", "w"); fwrite($file, json_encode($result, JSON_PRETTY_PRINT)); fclose($file); $web_driver->quit(); ?> from selenium import webdriver desired_cap = { 'platform': 'WIN10', 'browserName': 'chrome', 'version': 'latest-1', 'name': 'Accessibility Testing' } driver = webdriver.Remote( desired_capabilities=desired_cap, command_executor='http://key:secret@hub.testingbot.com/wd/hub', ) driver.get("https://testingbot.com") result = driver.execute_script('tb:accessibility') file = open("path/to/report.json", "w") file.write(str(result)) file.close() driver.quit() const { Builder, until } = require('selenium-webdriver'); const fs = require('fs/promises'); const TESTINGBOT_KEY = process.env.TB_KEY || 'api_key'; const TESTINGBOT_SECRET = process.env.TB_SECRET || 'api_secret'; const capabilities = { browserName: 'firefox', platform: 'WIN10', version: 'latest', name: 'Accessibility Test' }; async function runAccessibilityTest() { let driver; try { driver = await new Builder() .usingServer(`https://${TESTINGBOT_KEY}:${TESTINGBOT_SECRET}@hub.testingbot.com/wd/hub`) .withCapabilities(capabilities) .build(); await driver.get('https://testingbot.com'); const result = await driver.executeScript('tb:accessibility'); const filePath = 'accessibility-report.json'; await fs.writeFile(filePath, JSON.stringify(result, null, 2)); console.log(`✅ Accessibility report saved to ${filePath}`); } catch (error) { console.error('❌ Test failed:', error); } finally { if (driver) { await driver.quit(); } } } runAccessibilityTest(); using System; using OpenQA.Selenium; using OpenQA.Selenium.Remote; namespace SeleniumTest { class Program { static readonly string report = @"/path/where/you/want/to/save/report.json"; static void Main(string[] args) { IWebDriver driver; DesiredCapabilities capability = DesiredCapabilities.Chrome(); capability.SetCapability("key", "key"); capability.SetCapability("secret", "secret"); capability.SetCapability("version", "latest-1"); driver = new RemoteWebDriver( new Uri("https://hub.testingbot.com/wd/hub/"), capability ); driver.Navigate().GoToUrl("https://testingbot.com"); string result = (string)driver.ExecuteScript("tb:accessibility"); File.WriteAllText(report, result); driver.Quit(); } } } You could write `assertions` to pass/fail your test depending on the accessibility issues found. ## Results After running the example test, you will find a `report.json` file with the results of the accessibility test. The file will contain the following structure: { testEngine: {…} passes: […] inapplicable: [] url: "..." timestamp: "time when the result was generated" testRunner: {…} toolOptions: {…} testEnvironment: {…} violations: {…} incomplete: {…} } - `violations` includes the rules that were violated and need to be fixed. - `passes` the rules that have passed successfully. - `incomplete` incomplete results, either due to an error or aborted test - `inapplicable` no matching content was found for these rules. An overview of all accessibility rules that will be checked can be found on [A11Y rules overview](https://testingbot.com/support/accessibility/web/rules). Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/accessibility/web/rules # Accessibility Web Testing Rules Below is an overview of all the A11Y rules that TestingBot uses during automated web accessibility testing. Click a rule to see an explanation of the check and how to fix potential problems. ## Accessibility ruleset WCAG 2.0 Level A & AA Rules Rule ID | Description || [area-alt](https://testingbot.com/support/accessibility/web/rules/area-alt) | Ensure \ elements of image maps have alternative text | | [aria-allowed-attr](https://testingbot.com/support/accessibility/web/rules/aria-allowed-attr) | Ensure an element's role supports its ARIA attributes | | [aria-braille-equivalent](https://testingbot.com/support/accessibility/web/rules/aria-braille-equivalent) | Make sure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent | | [aria-command-name](https://testingbot.com/support/accessibility/web/rules/aria-command-name) | ARIA commands must have an accessible name | | [aria-conditional-attr](https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr) | Ensure ARIA attributes are used as described in the specification of the element's role | | [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) | Make sure elements do not use deprecated roles | | [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) | Make sure aria-hidden="true" is not present on the document body. | | [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) | Ensure aria-hidden elements are not focusable nor contain focusable elements | | [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) | Ensure every ARIA input field has an accessible name | | [aria-meter-name](https://testingbot.com/support/accessibility/web/rules/aria-meter-name) | Make sure every ARIA meter node has an accessible name | | [aria-progressbar-name](https://testingbot.com/support/accessibility/web/rules/aria-progressbar-name) | Every ARIA progressbar node must have an accessible name | | [aria-prohibited-attr](https://testingbot.com/support/accessibility/web/rules/aria-prohibited-attr) | Ensure ARIA attributes are not prohibited for an element's role | | [aria-required-attr](https://testingbot.com/support/accessibility/web/rules/aria-required-attr) | Make sure elements with ARIA roles have all required ARIA attributes | | [aria-required-children](https://testingbot.com/support/accessibility/web/rules/aria-required-children) | Ensure elements with an ARIA role that require child roles contain them | | [aria-required-parent](https://testingbot.com/support/accessibility/web/rules/aria-required-parent) | Make sure elements with an ARIA role that require parent roles are contained by them | | [aria-roles](https://testingbot.com/support/accessibility/web/rules/aria-roles) | Ensure all elements with a role attribute use a valid value | | [aria-toggle-field-name](https://testingbot.com/support/accessibility/web/rules/aria-toggle-field-name) | Make sure every ARIA toggle field has an accessible name | | [aria-tooltip-name](https://testingbot.com/support/accessibility/web/rules/aria-tooltip-name) | Ensure every ARIA tooltip node has an accessible name | | [aria-valid-attr-value](https://testingbot.com/support/accessibility/web/rules/aria-valid-attr-value) | Make sure all ARIA attributes have valid values | | [aria-valid-attr](https://testingbot.com/support/accessibility/web/rules/aria-valid-attr) | Ensure attributes that begin with aria- are valid ARIA attributes | | [blink](https://testingbot.com/support/accessibility/web/rules/blink) | Make sure \ elements are not used | | [button-name](https://testingbot.com/support/accessibility/web/rules/button-name) | Ensure buttons have discernible text | | [bypass](https://testingbot.com/support/accessibility/web/rules/bypass) | Ensure each page has at least one mechanism for a user to bypass navigation and jump straight to the content | | [color-contrast](https://testingbot.com/support/accessibility/web/rules/color-contrast) | Make sure each page has at least one mechanism for a user to bypass navigation and jump straight to the content | | [definition-list](https://testingbot.com/support/accessibility/web/rules/definition-list) | Ensure \ elements are structured correctly | | [dlitem](https://testingbot.com/support/accessibility/web/rules/dlitem) | Ensure \ and \ elements are contained by a \ | | [document-title](https://testingbot.com/support/accessibility/web/rules/document-title) | Make sure each HTML document contains a non-empty \ element | | [duplicate-id-aria](https://testingbot.com/support/accessibility/web/rules/duplicate-id-aria) | Ensure every id attribute value used in ARIA and in labels is unique | | [form-field-multiple-labels](https://testingbot.com/support/accessibility/web/rules/form-field-multiple-labels) | Ensure form field does not have multiple label elements | | [frame-focusable-content](https://testingbot.com/support/accessibility/web/rules/frame-focusable-content) | Ensure \ and \ elements with focusable content do not have tabindex=-1 | | [frame-title-unique](https://testingbot.com/support/accessibility/web/rules/frame-title-unique) | Ensure \ and \ elements contain a unique title attribute | | [frame-title](https://testingbot.com/support/accessibility/web/rules/frame-title) | Make sure \ and \ elements have an accessible name | | [html-has-lang](https://testingbot.com/support/accessibility/web/rules/html-has-lang) | Ensure every HTML document has a lang attribute | | [html-lang-valid](https://testingbot.com/support/accessibility/web/rules/html-lang-valid) | Ensure the lang attribute of the \ element has a valid value | | [html-xml-lang-mismatch](https://testingbot.com/support/accessibility/web/rules/html-xml-lang-mismatch) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | | [image-alt](https://testingbot.com/support/accessibility/web/rules/image-alt) | Ensure \ elements have alternative text or a role of none or presentation | | [input-button-name](https://testingbot.com/support/accessibility/web/rules/input-button-name) | Ensure input buttons have discernible text | | [input-image-alt](https://testingbot.com/support/accessibility/web/rules/input-image-alt) | Ensure \ elements have alternative text | | [label](https://testingbot.com/support/accessibility/web/rules/label) | Ensure every form element has a label | | [link-in-text-block](https://testingbot.com/support/accessibility/web/rules/link-in-text-block) | Ensure links are distinguished from surrounding text in a way that does not rely on color | | [link-name](https://testingbot.com/support/accessibility/web/rules/link-name) | Ensure links have discernible text | | [list](https://testingbot.com/support/accessibility/web/rules/list) | Ensure that lists are structured correctly | | [listitem](https://testingbot.com/support/accessibility/web/rules/listitem) | Ensure \ elements are used semantically | | [marquee](https://testingbot.com/support/accessibility/web/rules/marquee) | Ensure \ elements are not used | | [meta-refresh](https://testingbot.com/support/accessibility/web/rules/meta-refresh) | Ensure \ is not used for delayed refresh | | [meta-viewport](https://testingbot.com/support/accessibility/web/rules/meta-viewport) | Ensure \ does not disable text scaling and zooming | | [nested-interactive](https://testingbot.com/support/accessibility/web/rules/nested-interactive) | Ensure interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies | | [no-autoplay-audio](https://testingbot.com/support/accessibility/web/rules/no-autoplay-audio) | Ensure \ or \ elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio | | [object-alt](https://testingbot.com/support/accessibility/web/rules/object-alt) | Ensure \ elements have alternative text | | [role-img-alt](https://testingbot.com/support/accessibility/web/rules/role-img-alt) | Ensure [role="img"] elements have alternative text | | [scrollable-region-focusable](https://testingbot.com/support/accessibility/web/rules/scrollable-region-focusable) | Ensure elements that have scrollable content are accessible by keyboard | | [select-name](https://testingbot.com/support/accessibility/web/rules/select-name) | Ensure select element has an accessible name | | [server-side-image-map](https://testingbot.com/support/accessibility/web/rules/server-side-image-map) | Ensure that server-side image maps are not used | | [summary-name](https://testingbot.com/support/accessibility/web/rules/summary-name) | Ensure summary elements have discernible text | | [svg-img-alt](https://testingbot.com/support/accessibility/web/rules/svg-img-alt) | Ensure \ elements with an img, graphics-document or graphics-symbol role have an accessible text | | [td-headers-attr](https://testingbot.com/support/accessibility/web/rules/td-headers-attr) | Ensure that each cell in a table that uses the headers attribute refers only to other \ elements in that table | | [th-has-data-cells](https://testingbot.com/support/accessibility/web/rules/th-has-data-cells) | Ensure that \ elements and elements with role=columnheader/rowheader have data cells they describe | | [valid-lang](https://testingbot.com/support/accessibility/web/rules/valid-lang) | Ensure lang attributes have valid values | | [video-caption](https://testingbot.com/support/accessibility/web/rules/video-caption) | Ensure \ elements have captions | ## Accessibility ruleset WCAG 2.1 Level A & AA Rules Rule ID | Description || [autocomplete-valid](https://testingbot.com/support/accessibility/web/rules/autocomplete-valid) | Ensure the autocomplete attribute is correct and suitable for the form field | | [avoid-inline-spacing](https://testingbot.com/support/accessibility/web/rules/avoid-inline-spacing) | Ensure that text spacing set through style attributes can be adjusted with custom stylesheets | ## Accessibility ruleset WCAG 2.2 Level A & AA Rules Rule ID | Description || [target-size](https://testingbot.com/support/accessibility/web/rules/target-size) | Ensure touch targets have sufficient size and space | ## Best Practices Rule ID | Description || [accesskeys](https://testingbot.com/support/accessibility/web/rules/accesskeys) | Ensure every accesskey attribute value is unique | | [aria-allowed-role](https://testingbot.com/support/accessibility/web/rules/aria-allowed-role) | Ensure role attribute has an appropriate value for the element | | [aria-dialog-name](https://testingbot.com/support/accessibility/web/rules/aria-dialog-name) | Ensure every ARIA dialog and alertdialog node has an accessible name | | [aria-text](https://testingbot.com/support/accessibility/web/rules/aria-text) | Make sure role="text" is used on elements with no focusable descendants | | [aria-treeitem-name](https://testingbot.com/support/accessibility/web/rules/aria-treeitem-name) | Make sure every ARIA treeitem node has an accessible name | | [empty-heading](https://testingbot.com/support/accessibility/web/rules/empty-heading) | Make sure headings have discernible text | | [empty-table-header](https://testingbot.com/support/accessibility/web/rules/empty-table-header) | Ensure table headers have discernible text | | [heading-order](https://testingbot.com/support/accessibility/web/rules/heading-order) | Ensure the order of headings is semantically correct | | [image-redundant-alt](https://testingbot.com/support/accessibility/web/rules/image-redundant-alt) | Ensure image alternative is not repeated as text | | [label-title-only](https://testingbot.com/support/accessibility/web/rules/label-title-only) | Make sure that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes | | [landmark-banner-is-top-level](https://testingbot.com/support/accessibility/web/rules/landmark-banner-is-top-level) | Ensure the banner landmark is at top level | | [landmark-complementary-is-top-level](https://testingbot.com/support/accessibility/web/rules/landmark-complementary-is-top-level) | Make sure the complementary landmark or aside is at top level | | [landmark-contentinfo-is-top-level](https://testingbot.com/support/accessibility/web/rules/landmark-contentinfo-is-top-level) | Make sure the contentinfo landmark is at top level | | [landmark-main-is-top-level](https://testingbot.com/support/accessibility/web/rules/landmark-main-is-top-level) | Ensure the main landmark is at top level | | [landmark-no-duplicate-banner](https://testingbot.com/support/accessibility/web/rules/landmark-no-duplicate-banner) | Make sure the document has at most one banner landmark | | [landmark-no-duplicate-contentinfo](https://testingbot.com/support/accessibility/web/rules/landmark-no-duplicate-contentinfo) | Ensure the document has at most one contentinfo landmark | | [landmark-no-duplicate-main](https://testingbot.com/support/accessibility/web/rules/landmark-no-duplicate-main) | Make sure the document has at most one main landmark | | [landmark-one-main](https://testingbot.com/support/accessibility/web/rules/landmark-one-main) | Ensure the document has a main landmark | | [landmark-unique](https://testingbot.com/support/accessibility/web/rules/landmark-unique) | Ensure landmarks are unique | | [meta-viewport-large](https://testingbot.com/support/accessibility/web/rules/meta-viewport-large) | Ensure \ can scale a significant amount | | [page-has-heading-one](https://testingbot.com/support/accessibility/web/rules/page-has-heading-one) | Ensure that the page, or at least one of its frames contains a level-one heading | | [presentation-role-conflict](https://testingbot.com/support/accessibility/web/rules/presentation-role-conflict) | Ensure elements marked as presentational do not have global ARIA or tabindex so that all screen readers ignore them | | [region](https://testingbot.com/support/accessibility/web/rules/region) | Ensure all page content is contained by landmarks | | [scope-attr-valid](https://testingbot.com/support/accessibility/web/rules/scope-attr-valid) | Make sure the scope attribute is used correctly on tables | | [skip-link](https://testingbot.com/support/accessibility/web/rules/skip-link) | Ensure all skip links have a focusable target | | [tabindex](https://testingbot.com/support/accessibility/web/rules/tabindex) | Make sure tabindex attribute values are not greater than 0 | | [table-duplicate-name](https://testingbot.com/support/accessibility/web/rules/table-duplicate-name) | Make sure the \ element does not contain the same text as the summary attribute | | [color-contrast-enhanced](https://testingbot.com/support/accessibility/web/rules/color-contrast-enhanced) | Ensure the contrast between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds | | [identical-links-same-purpose](https://testingbot.com/support/accessibility/web/rules/identical-links-same-purpose) | Ensure that links with the same accessible name serve a similar purpose | | [meta-refresh-no-exceptions](https://testingbot.com/support/accessibility/web/rules/meta-refresh-no-exceptions) | Ensure \ is not used for delayed refresh | ## Experimental Rules Rule ID | Description || [css-orientation-lock](https://testingbot.com/support/accessibility/web/rules/css-orientation-lock) | Make sure content is not locked to any specific display orientation, and the content is operable in all display orientations | | [focus-order-semantics](https://testingbot.com/support/accessibility/web/rules/focus-order-semantics) | Ensure elements in the focus order have a role appropriate for interactive content | | [hidden-content](https://testingbot.com/support/accessibility/web/rules/hidden-content) | Inform users about hidden content. | | [label-content-name-mismatch](https://testingbot.com/support/accessibility/web/rules/label-content-name-mismatch) | Ensure that elements labelled through their content must have their visible text as part of their accessible name | | [p-as-heading](https://testingbot.com/support/accessibility/web/rules/p-as-heading) | Make sure bold, italic text and font-size is not used to style \ elements as a heading | | [table-fake-caption](https://testingbot.com/support/accessibility/web/rules/table-fake-caption) | Ensure that tables with a caption use the \ element. | | [td-has-header](https://testingbot.com/support/accessibility/web/rules/td-has-header) | Ensure that each non-empty data cell in a \ larger than 3 by 3 has one or more table headers | Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions # TestingBot Functions With functions you can perform various actions on the TestingBot browsers, without writing any code. Please see the list of currently available functions below: - [Take screenshots](https://testingbot.com/support/functions/screenshot) - [Generate PDFs](https://testingbot.com/support/functions/pdf) - [Scrape Webpages](https://testingbot.com/support/functions/scrape) - [Serverless Functions](https://testingbot.com/support/functions/serverless) Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions/screenshot # Screenshot Function This function will take a screenshot of the page you specified and return the image in `.png` or `.jpg` format. You can take one or more screenshots, in parallel, on different browsers and operating systems without having to write any code. Simply use the HTTP requests listed below in your app to generate a live screenshot of any page, on a real TestingBot browser. ## Example curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com"}' > screenshot.png This simple example will run a Puppeteer script on our service and do the following: - Start a Headless Browser (latest version) on our cloud - Connect with Puppeteer to the Browser and navigate to the URL you specified - Take a screenshot of the page - Return the `PNG data` back to you - The `PNG data` is saved in a file called `screenshot.png` ## Specifying browser and version See the example below to specify on which platform configuration you'd like to take your screenshot on. You can specify a `browserName`, `version` and `platform`. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Screenshot Options You can specify additional options with this function call to customize the screenshot taking. This function call can use any of the Puppeteer [page.screenshot](https://pptr.dev/api/puppeteer.screenshotoptions/) options. curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "options":{"fullPage":true}}' > screenshot.png ### Authenticate options You can specify the [page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate/) credentials. curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10" \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "authenticate":{ "username": "user", "password": "passwd" }}' > screenshot.png ### Goto options You can specify the [page.goto](https://pptr.dev/api/puppeteer.page.goto/) options and add `timeout` and `waitUntil` settings. curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "gotoOptions":{ "waitUntil": "networkidle2" }}' > screenshot.png ### Extra Headers You can specify the [page.setExtraHTTPHeaders](https://pptr.dev/api/puppeteer.page.setextrahttpheaders/) options to add extra HTTP headers to the request our Headless Browser makes. curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "extraHeaders":{ 'foo': 'bar' }}' > screenshot.png ### Disable Javascript You can disable Javascript with the [page.setJavaScriptEnabled](https://pptr.dev/api/puppeteer.page.setjavascriptenabled/) option. curl -X POST https://cloud.testingbot.com/screenshot?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "javascriptEnabled":false}' > screenshot.png ### Add Tags - You can add additional `style tags` with the [page.addStyleTag](https://pptr.dev/api/puppeteer.page.addstyletag) option. - You can add additional `script tags` with the [page.addScriptTag](https://pptr.dev/api/puppeteer.page.addscripttag/) option. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions/pdf # PDF Function This function will generate a PDF from any webpage. TestingBot will launch a remote browser, visit the URL you specified and take a PDF from it. Use the URLs below to take an instant PDF from a page, without having to write any code. Instead of relying on tools such as wkhtmltopdf, PDFShift, Athena, PDFBlade or others, you can rely on the power of Chrome's rendering engine to take a high quality PDF through a Function (which uses Puppeteer behind the scenes). ## Example curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com"}' > test.pdf This simple example will run a Puppeteer script on our service and do the following: - Start a Headless Browser (latest version) on our cloud - Connect with Puppeteer to the Browser and navigate to the URL you specified - Generate a PDF from the page - Return the `PDF file` back to you, in a file called `test.pdf` ## Specifying browser and version See the example below to specify on which platform configuration you'd like to generate the PDF on. You can specify a `browserName`, `version` and `platform`. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## PDF Options You can specify additional options with this function call to customize the PDF taking. This function call can use any of the Puppeteer [puppeteer.pdfoptions](https://pptr.dev/api/puppeteer.pdfoptions) options. curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "options":{"fullPage":true}}' > test.pdf ### Authenticate options You can specify the [page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate/) credentials. curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10" \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "authenticate":{ "username": "user", "password": "passwd" }}' > test.pdf ### Goto options You can specify the [page.goto](https://pptr.dev/api/puppeteer.page.goto) options and add `timeout` and `waitUntil` settings. curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "gotoOptions":{ "waitUntil": "networkidle2" }}' > test.pdf ### Extra Headers You can specify the [page.setExtraHTTPHeaders](https://pptr.dev/api/puppeteer.page.setextrahttpheaders) options to add extra HTTP headers to the request that the TestingBot browser makes. curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "extraHeaders":{ 'foo': 'bar' }}' > test.pdf ### Disable Javascript You can disable Javascript with the [page.setJavaScriptEnabled](https://pptr.dev/api/puppeteer.page.setjavascriptenabled) option. curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "javascriptEnabled":false}' > test.pdf ### Emulate Media Change the CSS media type of the page with [page.emulateMediaType](https://pptr.dev/api/puppeteer.page.emulatemediatype). curl -X POST https://cloud.testingbot.com/pdf?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "emulateMedia":"print"}' > test.pdf Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions/scrape # Scrape Function With the Scrape function you can visit any webpage on the internet with a remote, real browser running on TestingBot. You can fetch specific elements from the page and TestingBot will return it as a structured JSON response. By default, TestingBot will navigate to the URL and wait for all content to be loaded. TestingBot will then wait up to 30 seconds for an element to appear, assuming it is not yet in the DOM. ## Structured data The Scrape function can returned structured data for several specific use cases. See the list below on what we currently support: - [Amazon Products Scraper API](https://testingbot.com/support/functions/scrape/amazon-products) ## Example curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "elements":[{"selector":"body h2"}]}' This simple example will run a Puppeteer script on our service and do the following: - Start a Headless Browser (latest version) on our cloud - Connect with Puppeteer to the Browser and navigate to the URL you specified - Look for any elements in the DOM that match the selector `body h2` - Return a JSON response with the results that are found, see the example response below. [{"selector":"body h2","results":[{"html":"Automated Testing","text":"","width":340,"height":84,"top":1852.40625,"left":780,"attributes":[]},{"html":"Live Testing","text":"","width":150,"height":84,"top":2727.890625,"left":-146.71875,"attributes":[]},{"html":"+4800 Browsers & Devices","text":"","width":184,"height":168,"top":3455.265625,"left":780,"attributes":[]},{"html":"Integrate TestingBot into your setup","text":"Integrate TestingBot into your setup","width":549,"height":35,"top":2097.9375,"left":117.03125,"attributes":[]}]}] ## Specifying browser and version See the example below to specify on which platform configuration you'd like to scrape a webpage on. You can specify a `browserName`, `version` and `platform`. ![OS selected](https://testingbot.com/assets/environments/svg/windows11-0e1b28bc0fdd5034d3e4d3dc8d346c500a8c6522facf4b45d0da56537c1f1c6d.svg)Windows 11› ![Browser selected](https://testingbot.com/assets/environments/svg/chrome-c4081ff447d2d898d4afcb8f074a907c960e6f007716c1a1d119eee6803c4042.svg)Chrome 139 Loading environments... Please wait while we load the available browsers and platforms. ## Scrape Options You can specify additional options to use while using the scrape functionality. ### Authenticate options You can specify the [page.authenticate](https://pptr.dev/api/puppeteer.page.authenticate) credentials. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "authenticate":{ "username": "user", "password": "passwd" }, "elements":[{"selector":"body h2"}]}' ### Goto options You can specify the [page.goto](https://pptr.dev/api/puppeteer.page.goto) options and add `timeout` and `waitUntil` settings. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "gotoOptions":{ "waitUntil": "networkidle2" }, "elements":[{"selector":"body h2"}]}' ### Extra Headers You can specify the [page.setExtraHTTPHeaders](https://pptr.dev/api/puppeteer.page.setextrahttpheaders) options to add extra HTTP headers to the request that the TestingBot browser makes. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "extraHeaders":{ 'foo': 'bar' }, "elements":[{"selector":"body h2"}]}' ### Disable Javascript You can disable Javascript with the [page.setJavaScriptEnabled](https://pptr.dev/api/puppeteer.page.setjavascriptenabled) option. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "javascriptEnabled":false, "elements":[{"selector":"body h2"}]}' ### Emulate Media Change the CSS media type of the page with [page.emulateMediaType](https://pptr.dev/api/puppeteer.page.emulatemediatype). curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET&browserName=chrome&version=latest&platform=WIN10 \ -H 'Content-Type: application/json' \ -d '{"url":"https://testingbot.com", "emulateMedia":"print", "elements":[{"selector":"body h2"}]}' Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions/scrape/amazon-products # Scraping Amazon Products Stay on top of your competitors products and pricing strategies by monitoring millions of Amazon product listings, with a real remote browser. Fetch detailed information about any Amazon product, including title, price, description, images, reviews and more. TestingBot provides a scrape function which you cna call with an Amazon product ASIN, and it will return a structured JSON response with all the details of the product. ## Example curl -X POST https://cloud.testingbot.com/scrape/amazon-product?key=YOUR_KEY&secret=YOUR_SECRET \ -H 'Content-Type: application/json' \ -d '{"asin":"{AMAZON_ASIN}"} Replace `{AMAZON_ASIN}` with the actual ASIN of the product you want to scrape. The response will contain all the details of the product, including title, price, description, images, reviews and more. { "name": "Amazon Product Name", "product_information": { "product_dimensions": "8.1 x 8.1 x 0.04 inches", "item_weight": "3.52 ounces", "asin": "ACD3L74ZSQ", "item_model_number": "AV192", "customer_reviews": { "ratings_count": 14, "stars": 4.2 }, "best_sellers_rank": [ "#308,205 in Home & Kitchen (See Top 100 in Home & Kitchen)" ], "is_discontinued_by_manufacturer": null, "date_first_available": null, "manufacturer": "TB,LTD", "country_of_origin": null }, "brand": "Brand: TB", "brand_url": "/TB", "full_description": "The description", "pricing": "$12.98", "shipping_price": "Delivery Friday, August 22", "availability_quantity": null, "availability_status": "In Stock", "is_coupon_exists": true, "images": [ "https://m.media-amazon.com/images/I/82Dz8V7C3CL._AC_SX425_.jpg", ], "product_category": "Home & Kitchen", "average_rating": 4.2, "feature_bullets": [ "A cool scraper from TestingBot." ], "total_reviews": 14, "model": "AD195", "aplus_present": true } ## Example Some Amazon products are only available in specific countries, or the shipping price may vary based on the country. You can specify a `geoCountryCode` to scrape the product from a specific country. curl -X POST https://cloud.testingbot.com/scrape/amazon-product?key=YOUR_KEY&secret=YOUR_SECRET \ -H 'Content-Type: application/json' \ -d '{"asin":"{AMAZON_ASIN}", "geoCountryCode":"US"} Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/support/functions/serverless # /function This function endpoint allows you to `POST` Javascript code. TestingBot will run the Javascript code on the browser you specified and return the response generated from the code. ## Basic Example In the example below, we'll pass code that directly interfaces with Puppeteer. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET -H 'Content-Type: application/json' \ -d '{ "code": "module.exports=async({page:a,context:b})=>{const{url:c}=b;await a.goto(c);const d=await a.content();return{data:d,type:\\\"application/html\\\"}};", "context": { "url": "https://testingbot.com/" } }' We use the `page` object, which is a [Puppeteer Page Object](https://pptr.dev/api/puppeteer.page) and `context` which you can compare with function arguments that we pass in as an object. The example above will open a new browser session and execute the code in the `code` with `context` as arguments. Once the function has completed, you will receive the response. ## Advanced Example You can run other Javascript code in the serverless function as well, for example let's say you want to calculate something. Ofcourse this is a trivial example, but it shows the capabilities of running arbitrary Javascript code in the cloud. curl -X POST https://cloud.testingbot.com/scrape?key=YOUR_KEY&secret=YOUR_SECRET -H 'Content-Type: application/json' \ -d '{ "code": "module.exports=async()=>{const d = 4+4; return{data:d,type:\"application/html\"}};", "context": {} }' This will run a function that simply does a `4 + 4` calculation and return the result. Was this page helpful? Yes No ## Looking for More Help? Have questions or need more information? You can reach us via the following channels: - [Email us](https://testingbot.com/contact/new) - [Join our Slack Channel](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw) --- URL: https://testingbot.com/browserstack-alternative TestingBot vs BrowserStack # TestingBot, the #1 BrowserStack Alternative Run automated, visual and manual tests on **real desktop browsers and physical mobile devices** , without having to pay extra. We provide a **30% discount coupon** if you have previously purchased a competing product and want to switch to TestingBot. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) - 1+bn Tests Executed - 180k Active Users - 5,500+ Browsers & Devices ![Automated Testing](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) Trusted by some of the world's most innovative companies ## How TestingBot compares to BrowserStack TestingBot provides more for less. Transparent pricing, no hidden charges. Save 71% TestingBot BrowserStack $50 / month Billed annually $175 / month Billed annually Real Devices for Automated Testing Billed separately Manual Testing Billed separately Codeless Automation Billed separately Real Devices for Live Testing Single-Use machines BrowserStack re-uses the same machines for multiple users. TestingBot provides single-use machines: you always start with a clean machine. – Mobile Debugging Unlimited Users – Linux Virtual Machines – Simulators & Emulators TestingBot provides both real devices & simulators/emulators. Simulators & emulators are useful for quick initial testing. – Visual Testing Billed separately Accessibility Testing Billed separately How it works ## How TestingBot works ## Comprehensive coverage TestingBot provides thousands of real desktop browsers and physical mobile devices. Just like BrowserStack, we provide access to all popular browsers, including: Chrome, Firefox, Safari, Google Chrome, Microsoft Edge, Opera and more. [View supported browsers and devices](https://testingbot.com/support/web-automate/browsers) ![+5200 Browsers & Devices](https://testingbot.com/assets/alternatives/browsers-326041a6ac96d9681e3cf491f3cc00e81dc3e1fbcca91646da584cd787741286.jpg) ## Test Automation Frameworks TestingBot supports these popular Test Automation Frameworks: [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/features/automation/selenium) ### [Selenium](https://testingbot.com/features/automation/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/features/automation/appium) ### [Appium](https://testingbot.com/features/automation/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)](https://testingbot.com/features/automation/cypress) ### [Cypress](https://testingbot.com/features/automation/cypress) Javascript based E2E testing on Chrome and Firefox. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/features/automation/puppeteer) ### [Puppeteer](https://testingbot.com/features/automation/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/features/automation/playwright) ### [Playwright](https://testingbot.com/features/automation/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. [![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)](https://testingbot.com/features/automation/espresso) ### [Espresso](https://testingbot.com/features/automation/espresso) Android Automation Framework, runs on physical devices and emulators. [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)](https://testingbot.com/features/automation/xcuitest) ### [XCUITest](https://testingbot.com/features/automation/xcuitest) iOS Automation Framework, runs on physical devices and simulators. [![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)](https://testingbot.com/support/app-automate/maestro) ### [Maestro](https://testingbot.com/features/automation/maestro) Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Test on real mobile & desktop devices Get one-click access to real browsers running on macOS, Windows and Linux platforms. Cross-browser testing made simple: switch platforms, locations and screen resolutions instantly. Test across all versions of Internet Explorer (IE8 to IE11), Edge, Chrome, Safari, Firefox and Opera. [Get started free](https://testingbot.com/users/sign_up) ## Parallel Testing Drastically shorten your total test duration by running tests simultaneously. TestingBot provides single-use VMs on Windows, Linux and macOS, optimized for speed and stability. TestingBot's pricing per parallel test is much more affordable than BrowserStack. [View our pricing](https://testingbot.com/pricing) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ![Test on real mobile & desktop devices](https://testingbot.com/assets/home/ai-chat-24cc1ab8234690bad4a866888a2bd8e11f1301b7e21ad86be5d4d61be838707a.webp) AI Testing ## AI Test Agent Use TestingBotAI End-to-End Testing Assistant to create and run tests for you. Simply write in natural language what the test should verify, and TestingBotAI will create all the test steps and run the test for you. [Start AI Testing](https://testingbot.com/features/ai-testing) ## Why people pick TestingBot over BrowserStack ### Transparent Pricing Many users discover the steep pricing of the multiple BrowserStack modules, each with their own separate pricing. TestingBot's pricing is straightforward and flat, with all features included. ### Support TestingBot prides itself on providing exceptional support to its users, ensuring that any issues are resolved quickly and efficiently. ### UX BrowserStack's UX is slow to navigate, complex and unintuitive, making it difficult for users to find the features they need. TestingBot offers a more streamlined and user-friendly interface, allowing for easier access to all testing tools and features. ### Emulators & Simulators BrowserStack prides itself for not providing emulators & simulators. TestingBot provides both real devices and emulators/simulators for comprehensive testing. ### Security BrowserStack re-uses virtual machines across tests. TestingBot provides full access to each machine, as they are single-use and will not be re-used in other tests, by other users, possibly leaking sensitive data. ### AI Testing TestingBot offers an easy to use, AI powered test engine, capable of generating and executing tests based on natural language descriptions. > "Users often find that BrowserStack can overwhelm them with complex UX and lack of support. Others cite frustrations with BrowserStack's high costs once you use multiple features, making it tricky to get full coverage without breaking the budget." _G2 Reviewers_ ## Frequently Asked Questions ### Can I use TestingBot to replace both BrowserStack and other tools like Percy or LambdaTest? Yes, TestingBot provides a unified platform to replace both BrowserStack and other tools. Run manual, automated and visual tests against websites and mobile apps. TestingBot provides a large collection of browsers & mobile devices to test on. Run accessibility tests, geolocation testing and more at a much cheaper price. ### Why are devs and QA switching from BrowserStack to TestingBot? BrowserStack users report high costs, poor customer support and complex UX. TestingBot fixes all of that. ### Is it hard to switch from BrowserStack to TestingBot? No. Teams switching typically get up and running in less than a day. Some small configuration changes are needed and you'll be up and running with TestingBot in no time. ### How does TestingBot's pricing compare to BrowserStack's? TestingBot offers more affordable pricing plans compared to BrowserStack, making it a cost-effective solution for teams of all sizes. We do not charge extra for services such as physical device testing, accessibility testing, visual testing and more. ### Why would I choose TestingBot over BrowserStack? TestingBot is easier to use, delivers fewer false positives, offers better support and has a transparent pricing model that doesn't punish you for scale. ## Ready to get started? Start testing your website and mobile app today. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/lambdatest-alternative TestingBot vs LambdaTest # TestingBot, the #1 LambdaTest Alternative Run automated, visual and manual tests on **real desktop browsers and physical mobile devices** , without having to pay extra. We provide a **30% discount coupon** if you have previously purchased a LambdaTest product and want to switch to TestingBot. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) - 1+bn Tests Executed - 180k Active Users - 5,500+ Browsers & Devices ![Automated Testing](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) Trusted by some of the world's most innovative companies ## How TestingBot compares to LambdaTest TestingBot provides more for less. Transparent pricing, no hidden charges. Save 60% TestingBot LambdaTest $50 / month Billed annually $128 / month Billed annually Real Devices for Automated Testing Billed separately Codeless Automation Billed separately Native App Automation Billed separately Manual Testing Billed separately Real Devices for Live Testing Single-Use machines LambdaTest re-uses the same machines for multiple users. TestingBot provides single-use machines: you always start with a clean machine. – Mobile Debugging Linux Virtual Machines – Visual Testing Billed separately How it works ## How TestingBot works ## Comprehensive coverage TestingBot provides thousands of real desktop browsers and physical mobile devices. Just like LambdaTest, we provide access to all popular browsers, including: Chrome, Firefox, Safari, Google Chrome, Microsoft Edge, Opera and more. [View supported browsers and devices](https://testingbot.com/support/web-automate/browsers) ![+5200 Browsers & Devices](https://testingbot.com/assets/alternatives/browsers-326041a6ac96d9681e3cf491f3cc00e81dc3e1fbcca91646da584cd787741286.jpg) ## Test Automation Frameworks TestingBot supports these popular Test Automation Frameworks: [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/features/automation/selenium) ### [Selenium](https://testingbot.com/features/automation/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/features/automation/appium) ### [Appium](https://testingbot.com/features/automation/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)](https://testingbot.com/features/automation/cypress) ### [Cypress](https://testingbot.com/features/automation/cypress) Javascript based E2E testing on Chrome and Firefox. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/features/automation/puppeteer) ### [Puppeteer](https://testingbot.com/features/automation/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/features/automation/playwright) ### [Playwright](https://testingbot.com/features/automation/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. [![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)](https://testingbot.com/features/automation/espresso) ### [Espresso](https://testingbot.com/features/automation/espresso) Android Automation Framework, runs on physical devices and emulators. [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)](https://testingbot.com/features/automation/xcuitest) ### [XCUITest](https://testingbot.com/features/automation/xcuitest) iOS Automation Framework, runs on physical devices and simulators. [![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)](https://testingbot.com/support/app-automate/maestro) ### [Maestro](https://testingbot.com/features/automation/maestro) Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. ![Test on real mobile & desktop devices](https://testingbot.com/assets/features/manual-flow-b2c093218b8db3363e5903a6197ce47efa4361cd8c114738489bbc673b5d168a.jpg) ## Test on real mobile & desktop devices Get one-click access to real browsers running on macOS, Windows and Linux platforms. Cross-browser testing made simple: switch platforms, locations and screen resolutions instantly. Test across all versions of Internet Explorer (IE8 to IE11), Edge, Chrome, Safari, Firefox and Opera. [Get started free](https://testingbot.com/users/sign_up) ## Parallel Testing Drastically shorten your total test duration by running tests simultaneously. TestingBot provides single-use VMs on Windows, Linux and macOS, optimized for speed and stability. TestingBot's pricing per parallel test is much more affordable than LambdaTest. [View our pricing](https://testingbot.com/pricing) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ![Test on real mobile & desktop devices](https://testingbot.com/assets/home/ai-chat-24cc1ab8234690bad4a866888a2bd8e11f1301b7e21ad86be5d4d61be838707a.webp) AI Testing ## AI Test Agent Use TestingBotAI End-to-End Testing Assistant to create and run tests for you. Simply write in natural language what the test should verify, and TestingBotAI will create all the test steps and run the test for you. [Start AI Testing](https://testingbot.com/features/ai-testing) ## Why people pick TestingBot over LambdaTest ### Transparent Pricing Many users discover the steep pricing of the multiple LambdaTest modules, each with their own separate pricing. TestingBot's pricing is straightforward and flat, with all features included. ### Support TestingBot prides itself on providing exceptional support to its users, ensuring that any issues are resolved quickly and efficiently. ### UX LambdaTest's UX can be slow to navigate, complex and unintuitive, making it difficult for users to find the features they need. TestingBot offers a more streamlined and user-friendly interface. ### Documentation Lambdatest documentation is often incomplete and lacks detail, making it difficult for users to find the information they need. TestingBot provides comprehensive and detailed documentation, making it easy for users to get started and find answers to their questions. ### Security LambdaTest re-uses virtual machines across tests. TestingBot provides full access to each machine, as they are single-use and will not be re-used in other tests, by other users, possibly leaking sensitive data. ### AI Testing TestingBot offers an easy to use, AI powered test engine, capable of generating and executing tests based on natural language descriptions. > "Users often find that LambdaTest is slow to use, with slow startup times for browsers. Others cite frustrations with LambdaTest's pricing structure when using multiple features, making it difficult to get full coverage without unexpected expenses." _G2 Reviewers_ ## Frequently Asked Questions ### Can I use TestingBot to replace both LambdaTest and other tools like SauceLabs or BrowserStack? Yes, TestingBot provides a unified platform to replace both LambdaTest and other tools. Run manual, automated and visual tests against websites and mobile apps. TestingBot provides a large collection of browsers & mobile devices to test on. Run accessibility tests, geolocation testing and more at a much cheaper price. ### Why are devs and QA switching from LambdaTest to TestingBot? LambdaTest users report high costs for additional features, complex pricing models and limited support options. TestingBot fixes all of that. ### Is it hard to switch from LambdaTest to TestingBot? No. Teams switching typically get up and running in less than a day. Some small configuration changes are needed and you'll be up and running with TestingBot in no time. ### How does TestingBot's pricing compare to LambdaTest's? TestingBot offers more affordable pricing plans compared to LambdaTest, making it a cost-effective solution for teams of all sizes. We do not charge extra for services such as physical device testing, accessibility testing, visual testing and more. ### Why would I choose TestingBot over LambdaTest? TestingBot is easier to use, delivers fewer false positives, offers better support and has a transparent pricing model that doesn't punish you for scale. ## Ready to get started? Start testing your website and mobile app today. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/saucelabs-alternative TestingBot vs SauceLabs # TestingBot, the #1 SauceLabs Alternative Run automated, visual and manual tests on **real desktop browsers and physical mobile devices** , without having to pay extra. We provide a **30% discount coupon** if you have previously purchased a competing product and want to switch to TestingBot. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) - 1+bn Tests Executed - 180k Active Users - 5,500+ Browsers & Devices ![Automated Testing](https://testingbot.com/assets/hero/automated-f13c4f47b8139a589966d59465e1aae2e65dae155b106d3956ce990a302a80a4.webp) Trusted by some of the world's most innovative companies ## How TestingBot compares to SauceLabs TestingBot provides more for less. Transparent pricing, no hidden charges. Save 39% TestingBot SauceLabs $90 / month Billed annually $149 / month Billed annually Real Devices for Automated Testing Billed separately Codeless Automation - Real Devices for Live Testing Billed separately Single-Use machines Mobile Debugging Unlimited Users – Visual Testing Accessibility Testing - ## Why choose TestingBot as a SauceLabs alternative? ## Comprehensive coverage TestingBot provides thousands of real desktop browsers and physical mobile devices. Just like SauceLabs, we provide access to all popular browsers, including: Chrome, Firefox, Safari, Google Chrome, Microsoft Edge, Opera and more. [View supported browsers and devices](https://testingbot.com/support/web-automate/browsers) ![+5200 Browsers & Devices](https://testingbot.com/assets/alternatives/browsers-326041a6ac96d9681e3cf491f3cc00e81dc3e1fbcca91646da584cd787741286.jpg) ## Test Automation Frameworks TestingBot supports these popular Test Automation Frameworks: [![Selenium Testing](https://testingbot.com/assets/support/selenium-266ecc0599068fc6eca0bcd9174fb46053c95cebe1c66f7a50c480f3f1a52929.svg)](https://testingbot.com/features/automation/selenium) ### [Selenium](https://testingbot.com/features/automation/selenium) Popular Browser Automation Framework, using WebDriver, which supports all major browsers. [![Appium Testing](https://testingbot.com/assets/support/appium-4b35a8bb56bae236bd84c539cee9b8bbb489a55ddf48e32d059c86685d230354.svg)](https://testingbot.com/features/automation/appium) ### [Appium](https://testingbot.com/features/automation/appium) Mobile Automation Framework, using WebDriver, runs on physical devices and simulators/emulators. [![Cypress Testing](https://testingbot.com/assets/support/cypress-409c9fd3f79115ed7676aa1df4f6a217dc4402b3366a61984924aec7b4fefa97.svg)](https://testingbot.com/features/automation/cypress) ### [Cypress](https://testingbot.com/features/automation/cypress) Javascript based E2E testing on Chrome and Firefox. [![Puppeteer Testing](https://testingbot.com/assets/support/puppeteer-63fa36b36d91bc87cb056dbf2f9843947371e41400d473b4c0cc3729283af5dc.svg)](https://testingbot.com/features/automation/puppeteer) ### [Puppeteer](https://testingbot.com/features/automation/puppeteer) Chrome DevTools based Automation Framework by Google. Supports Chrome and Edge browsers. [![Playwright Testing](https://testingbot.com/assets/support/playwright-2dcb4e75b55ac0d1135cfa47be6137b13f46a2047ce78b96a34f51b0e2cc0d96.svg)](https://testingbot.com/features/automation/playwright) ### [Playwright](https://testingbot.com/features/automation/playwright) Similar to Puppeteer, built by Microsoft, with support for Chrome and Edge. [![Espresso Testing](https://testingbot.com/assets/integrations/espresso-a8ff30da0c385f89f4e694bb29fc4779ad132e8e3f4a777a38e608e0492ff610.svg)](https://testingbot.com/features/automation/espresso) ### [Espresso](https://testingbot.com/features/automation/espresso) Android Automation Framework, runs on physical devices and emulators. [![XCUITest](https://testingbot.com/assets/integrations/xcuitest-a9262c0277bf518323bfa442c87c9309681b673b52646bd772f9289c668f72fe.svg)](https://testingbot.com/features/automation/xcuitest) ### [XCUITest](https://testingbot.com/features/automation/xcuitest) iOS Automation Framework, runs on physical devices and simulators. [![Maestro Testing](https://testingbot.com/assets/integrations/maestro-9d782f30f13fb4efaf9928b704c7a787eb14cb9e5b20c650137bb65892334b8b.svg)](https://testingbot.com/support/app-automate/maestro) ### [Maestro](https://testingbot.com/features/automation/maestro) Maestro is a mobile UI testing framework, which supports testing on both iOS and Android. ## Parallel Testing Drastically shorten your total Selenium test duration by running tests simultaneously. TestingBot provides single-use VMs on Windows, Linux and macOS, optimized for speed and stability. TestingBot's pricing per parallel test is more affordable than SauceLabs. [View our pricing](https://testingbot.com/pricing) ![Parallel Testing](https://testingbot.com/assets/features/selenium/parallel-0229d698e59a8a6b92fe50344a08634624f018331ecf8a849ef83cfb35e635a5.png) ![Test on real mobile & desktop devices](https://testingbot.com/assets/home/ai-chat-24cc1ab8234690bad4a866888a2bd8e11f1301b7e21ad86be5d4d61be838707a.webp) AI Testing ## AI Test Agent Use TestingBotAI End-to-End Testing Assistant to create and run tests for you. Simply write in natural language what the test should verify, and TestingBotAI will create all the test steps and run the test for you. [Start AI Testing](https://testingbot.com/features/ai-testing) ## Why people pick TestingBot over SauceLabs ### Support People migrating from SauceLabs complain about their lack of support. TestingBot prides itself on providing exceptional support to its users, ensuring that any issues are resolved quickly and efficiently. ### Transparent Pricing Users realize the steep pricing of SauceLabs cannot be justified. TestingBot's pricing is much more affordable, with all features included. ### Lack of new features SauceLabs is slow to release new features. TestingBot was providing macOS remote machines running Apple Silicon over 10 months before SauceLabs announced support for it. ### You're just a number Even if you pay a premium for Account Managers, you still lack the support and attention you require. ### Documentation SauceLabs's documentation and code examples are all over the place, making it hard to get started. ### AI Testing TestingBot offers an easy to use, AI powered test engine, capable of generating and executing tests based on natural language descriptions. > "Users find that SauceLabs lacks support, documentation and helpful examples. Others cite frustrations with SauceLabs's high costs, making it tricky to get full coverage without breaking the budget." _G2 Reviewers_ ## Frequently Asked Questions ### Can I use TestingBot to replace both SauceLabs and other tools like BrowserStack or LambdaTest? Yes, TestingBot provides a unified platform to replace both SauceLabs and other tools. Run manual, automated and visual tests against websites and mobile apps. TestingBot provides a large collection of browsers & mobile devices to test on. Run accessibility tests, geolocation testing, physical device testing and more at a much cheaper price. ### Why are devs and QA switching from SauceLabs to TestingBot? SauceLabs users complain about high costs, lacking customer support and complex UX. TestingBot fixes all of that. ### Is it hard to switch from SauceLabs to TestingBot? No. Teams switching typically get up and running in less than a day. TestingBot provides the same features as SauceLabs, all you need to change are some configuration settings. ### How does TestingBot's pricing compare to SauceLabs's? TestingBot offers more affordable pricing plans compared to SauceLabs, making it a cost-effective solution for teams of all sizes. Physical device testing is included in all our plans, while SauceLabs charges extra. ### Why would I choose TestingBot over SauceLabs? TestingBot is easier to use, delivers fewer false positives, offers better support and has a transparent pricing model that doesn't punish you for scale. ## Ready to get started? Start testing your website and mobile app today. [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/resources/articles # Resource Center Articles [![Top Web Development Tools in 2025](https://testingbot.com/assets/resources/articles/55-68e8970c2d4f68ef0fe0f4f519991c5f4413c2c08802b5baba57baab219a239a.webp)](https://testingbot.com/resources/articles/web-development-tools "Top Web Development Tools in 2025") [ ## Top Web Development Tools in 2025 ](https://testingbot.com/resources/articles/web-development-tools "Top Web Development Tools in 2025") A top 10 list of the most popular and useful web development tools. [Read more](https://testingbot.com/resources/articles/web-development-tools) [![Most popular Screen Resolutions](https://testingbot.com/assets/resources/articles/54-5f84cd0ac4f2b96527545559c41f9e198b9bcb433dc32d6f58e33a4088ba4be1.webp)](https://testingbot.com/resources/articles/common-screen-resolutions "Most popular Screen Resolutions") [ ## Most popular Screen Resolutions ](https://testingbot.com/resources/articles/common-screen-resolutions "Most popular Screen Resolutions") An overview of the most popular screen resolutions in 2025 for desktop and mobile. [Read more](https://testingbot.com/resources/articles/common-screen-resolutions) [![Selenium Python Tutorial](https://testingbot.com/assets/resources/articles/51-39337d128e18d16ddec5fe39124c2302f334e0f21e06f361cfd19e0b719e8861.webp)](https://testingbot.com/resources/articles/python-selenium-web-automation-test "Selenium Python Tutorial") [ ## Selenium Python Tutorial ](https://testingbot.com/resources/articles/python-selenium-web-automation-test "Selenium Python Tutorial") A quick introduction in using Python with Selenium WebDriver [Read more](https://testingbot.com/resources/articles/python-selenium-web-automation-test) [![How to Change Browser Settings](https://testingbot.com/assets/resources/articles/52-5bb27f13382030a8890a4a9c2d53a015fac4512df32e6a633d59a27c6ccd71cf.webp)](https://testingbot.com/resources/articles/how-to-change-browser-settings "How to Change Browser Settings") [ ## How to Change Browser Settings ](https://testingbot.com/resources/articles/how-to-change-browser-settings "How to Change Browser Settings") Find out how to change browser settings on Chrome, Firefox and Microsoft Edge. [Read more](https://testingbot.com/resources/articles/how-to-change-browser-settings) [![What is isolation testing?](https://testingbot.com/assets/resources/articles/50-6cf90dd5ec7b54f52a74dd2870938d81958ac171ec40d066cb89de674bdc11a6.webp)](https://testingbot.com/resources/articles/isolation-test "What is isolation testing?") [ ## What is isolation testing? ](https://testingbot.com/resources/articles/isolation-test "What is isolation testing?") Isolation Testing means verifying the functionality of a specific part of software on its own, free from outside influences. [Read more](https://testingbot.com/resources/articles/isolation-test) [![Why is accessibility testing important in web design?](https://testingbot.com/assets/resources/articles/49-ddec8d6d134f657a98d9537849a0bb94fe908d49159be466aa83da15760120a4.webp)](https://testingbot.com/resources/articles/why-accessibility-testing "Why is accessibility testing important in web design?") [ ## Why is accessibility testing important in web design? ](https://testingbot.com/resources/articles/why-accessibility-testing "Why is accessibility testing important in web design?") Find out why it's important to think about accessibility when designing your webpages. [Read more](https://testingbot.com/resources/articles/why-accessibility-testing) [![Protect your Shopify store](https://testingbot.com/assets/resources/articles/47-93b1b2d2876da23984eced6f17b1690865746b54eaa11b0e9cbc17c9b0219e2d.webp)](https://testingbot.com/resources/articles/shopify-store-monitoring "Protect your Shopify store") [ ## Protect your Shopify store ](https://testingbot.com/resources/articles/shopify-store-monitoring "Protect your Shopify store") Learn how to monitor your Shopify store with the TestingBot App. [Read more](https://testingbot.com/resources/articles/shopify-store-monitoring) [![Top 15 AI Testing Tools](https://testingbot.com/assets/resources/articles/44-0566068e7f37e24257a058aa6ff3398f11e192e89be40e10d2e8a81335d16b6c.webp)](https://testingbot.com/resources/articles/top-15-ai-testing-tools "Top 15 AI Testing Tools") [ ## Top 15 AI Testing Tools ](https://testingbot.com/resources/articles/top-15-ai-testing-tools "Top 15 AI Testing Tools") Learn about the top 15 AI testing tools. [Read more](https://testingbot.com/resources/articles/top-15-ai-testing-tools) [![Run Maestro tests in the cloud](https://testingbot.com/assets/resources/articles/45-54aab6a840d2561eab846e8bfde7ec26113ba601a9fcc15ddea883c2a80ec29c.webp)](https://testingbot.com/resources/articles/maestro-cloud-testing "Run Maestro tests in the cloud") [ ## Run Maestro tests in the cloud ](https://testingbot.com/resources/articles/maestro-cloud-testing "Run Maestro tests in the cloud") Maestro cloud testing allows you to run Maestro flows on remote iOS and Android devices. [Read more](https://testingbot.com/resources/articles/maestro-cloud-testing) - [1](https://testingbot.com/resources/articles) - [2](https://testingbot.com/resources/articles?page=2) - [3](https://testingbot.com/resources/articles?page=3) - [4](https://testingbot.com/resources/articles?page=4) - [5](https://testingbot.com/resources/articles?page=5) - [...](https://testingbot.com#) - [Next](https://testingbot.com/resources/articles?page=2) --- URL: https://testingbot.com/resources/courses # Courses Follow courses and tutorials to learn more about TestingBot and technologies such as Selenium, Appium, Cypress, Espresso and XCUITest. [![Appium and WebDriverIO](https://testingbot.com/assets/resources/courses/3-16c2e4aeb71671a0c5f55a4e3a3904e094a9d0d4870edd12d4d3987785d46e9e.webp)](https://testingbot.com/resources/courses/appium-webdriverio "Appium and WebDriverIO") [ ## Appium and WebDriverIO ](https://testingbot.com/resources/courses/appium-webdriverio "Appium and WebDriverIO") Learn what WebDriverIO is and how you can use it in combination with Appium to do automated testing. - Duration: 10 minutes - Difficulty: Easy [Start course](https://testingbot.com/resources/courses/appium-webdriverio) [![Local website testing](https://testingbot.com/assets/resources/courses/2-246ca55ba62d127afa39a405c4cbb8c5561a172f5f6f5b43d9ecbcc7ff5b3232.webp)](https://testingbot.com/resources/courses/local-website-testing "Local website testing") [ ## Local website testing ](https://testingbot.com/resources/courses/local-website-testing "Local website testing") In this course we'll learn how to perform website testing against a website running on a local machine or private network. - Duration: 12 minutes - Difficulty: Medium [Start course](https://testingbot.com/resources/courses/local-website-testing) [![A Primer on Testing with TestingBot](https://testingbot.com/assets/resources/courses/1-8c736aa0fe0d0577791766e628cf8d20f291814618375635490323e249d980b0.webp)](https://testingbot.com/resources/courses/testing-with-testingbot "A Primer on Testing with TestingBot") [ ## A Primer on Testing with TestingBot ](https://testingbot.com/resources/courses/testing-with-testingbot "A Primer on Testing with TestingBot") Learn more on how to test with TestingBot - Duration: 10 minutes - Difficulty: Hard [Start course](https://testingbot.com/resources/courses/testing-with-testingbot) [![Selenium Basics: TestNG](https://testingbot.com/assets/resources/courses/4-c9c7ea484cda943a8c695f9fa07a8257fe9047e66338206dcde2d2f0664275df.webp)](https://testingbot.com/resources/courses/selenium-testng "Selenium Basics: TestNG") [ ## Selenium Basics: TestNG ](https://testingbot.com/resources/courses/selenium-testng "Selenium Basics: TestNG") Learn how to use TestNG in combination with Selenium to run automated, cross browser tests. - Duration: 30 minutes - Difficulty: Medium [Start course](https://testingbot.com/resources/courses/selenium-testng) [![Preparing for Selenium Interview Questions](https://testingbot.com/assets/resources/courses/5-4f357dbaaf3a9aa3aba0aa09f90b952bea202004b1d7da021c419a7359dbca0c.webp)](https://testingbot.com/resources/courses/selenium-interview-questions "Preparing for Selenium Interview Questions") [ ## Preparing for Selenium Interview Questions ](https://testingbot.com/resources/courses/selenium-interview-questions "Preparing for Selenium Interview Questions") This course will help you prepare for answering any questions you might receive during a Selenium interview. - Duration: 100 minutes - Difficulty: Medium [Start course](https://testingbot.com/resources/courses/selenium-interview-questions) --- URL: https://testingbot.com/resources/videos # Resource Center Videos [![Selenium testing with Python Tutorial](https://testingbot.com/assets/videos/python-automated-bacffb33401f4772664d4d9c06455f2c0e4fabed0bfadf10770c0535a2bb6e76.png)](https://testingbot.com/resources/videos/python-automated-testing-selenium "Selenium testing with Python Tutorial") [ ## Selenium testing with Python Tutorial ](https://testingbot.com/resources/videos/python-automated-testing-selenium "Selenium testing with Python Tutorial") Want to use Python with Selenium? See this video to learn more. [Read more](https://testingbot.com/resources/videos/python-automated-testing-selenium) [![Automated Browser Testing with Ruby](https://testingbot.com/assets/videos/ruby-automated-a49902d15d265750dcd04b07a1fe142d8aac47976a9cae828e47835c01ce798f.png)](https://testingbot.com/resources/videos/ruby-automated-testing-selenium "Automated Browser Testing with Ruby") [ ## Automated Browser Testing with Ruby ](https://testingbot.com/resources/videos/ruby-automated-testing-selenium "Automated Browser Testing with Ruby") Video tutorial on how to run Ruby Automated Test on TestingBot. [Read more](https://testingbot.com/resources/videos/ruby-automated-testing-selenium) [![Automated testing with PHP and Selenium](https://testingbot.com/assets/videos/php-automated-29a925d6233fb94334c6c833b7e41d3e1ba05e04c5a01dc163a0fddac15d6889.png)](https://testingbot.com/resources/videos/php-automated-testing-selenium "Automated testing with PHP and Selenium") [ ## Automated testing with PHP and Selenium ](https://testingbot.com/resources/videos/php-automated-testing-selenium "Automated testing with PHP and Selenium") Learn how to use PHP with Selenium to do automated browser testing. [Read more](https://testingbot.com/resources/videos/php-automated-testing-selenium) --- URL: https://testingbot.com/product-updates # Product Updates Stay up-to-date with TestingBot's latest product updates. 2026-01-04 ## Huawei P40 physical device with HarmonyOS ![Huawei P40 physical device with HarmonyOS](https://testingbot.com/assets/devices/160h/39-32a788c7e66a3da1c88eaaefefd37381f729e510f096b43906968b6907c44c57.webp) Huawei P40 physical device is now available for Automated and Live testing. This new device comes with HarmonyOS installed. 2025-12-22 ## iPhone Air physical device with iOS 26.2 ![iPhone Air physical device with iOS 26.2](https://testingbot.com/assets/devices/160h/38-c00a59944eb2e410d375e3f5b39780043f72446bb33b0aea6a26a0c45f309ea1.webp) iPhone Air physical device is now available for Automated and Live testing. This new device comes with iOS 26.2 installed. 2025-12-12 ## Pixel 10 physical device with Android 16 ![Pixel 10 physical device with Android 16](https://testingbot.com/assets/devices/160h/37-738ed465eff0a4bcc33a5294f6f9f4d701fed317ce0e97e202ffc3f9dca7edd4.webp) Pixel 10 physical device is now available for Automated and Live testing. This new device comes with Android 16 installed. 2025-11-10 ## TestingBot MCP Server TestingBot now supports the **Model Context Protocol (MCP)**, enabling seamless integration with Claude, Cursor and VS Code. Control tests using natural language. See how to set it up: [MCP Server documentation](https://testingbot.com/support/ai/mcp). 2025-11-05 ## iPhone 17 physical device with iOS 26 ![iPhone 17 physical device with iOS 26](https://testingbot.com/assets/devices/160h/36-06478e9d9935ed794bd3ec02c85ad3a8eafe1de3cc11debd15351c1bdc99005b.webp) iPhone 17 physical device is now available for Automated and Live testing. This new device comes with iOS 26 installed. 2025-11-05 ## Chrome 142, Edge 142, Firefox 144 and Opera 123 We have added the latest new browser versions for automated, manual and visual testing: - Chrome 142 - Microsoft Edge 142 - Firefox 144 - Opera 123 2025-09-12 ## Chrome 140, Microsoft Edge 140, Firefox 142 and Opera 121 We have added the latest new browser versions for automated, manual and visual testing: - Chrome 140 - Microsoft Edge 140 - Firefox 142 - Opera 121 2025-09-12 ## Appium 3 now available Appium 3 is now available on TestingBot for automated testing on iOS simulators, Android emulators and physical iOS+Android devices. Take advantage of Appium's latest release to run automated tests on mobile devices. Please see the [Appium versions documentation](https://testingbot.com/support/app-automate/appium/appium-versions) to get started. 2025-08-15 ## iOS 18.6 simulators iOS 18.6 simulators are now available for Automated and Manual testing. Test your apps and websites on iOS 18.6 with TestingBot. 2025-07-13 ## Maestro Testing on Android Real Devices You can now run [Maestro Mobile Tests](https://testingbot.com/support/app-automate/maestro) on TestingBot's physical Android devices. Run your **Maestro tests** on real hardware to ensure your app works perfectly in real-world conditions. 2025-07-13 ## Chrome 139, Microsoft Edge 139, Firefox 140 & Opera 120 We have added the latest new browser versions for automated, manual and visual testing: - Chrome 139 - Microsoft Edge 139 - Firefox 140 - Opera 120 - [1](https://testingbot.com/product-updates) - [2](https://testingbot.com/product-updates?page=2) - [3](https://testingbot.com/product-updates?page=3) - [4](https://testingbot.com/product-updates?page=4) - [5](https://testingbot.com/product-updates?page=5) - [...](https://testingbot.com#) - [Next](https://testingbot.com/product-updates?page=2) --- URL: https://testingbot.com/free-online-tools 100% Free Tools # Developer Tools Made Simple A curated collection of free online tools for developers, testers and designers. Format code, generate test data and convert between formats, all from within your browser. 30+ Free Tools Instant Results Private No Data Stored ## Code Formatter - [ ### JSON Prettifier Prettify JSON code online with this free tool. Try it free ](https://testingbot.com/free-online-tools/json-prettify) - [ ### HTML Escaper Escape HTML code online with this free tool. Try it free ](https://testingbot.com/free-online-tools/html-escape) - [ ### XML Prettifier Prettify your XML code online with this free tool. Try it free ](https://testingbot.com/free-online-tools/xml-prettify) - [ ### Remove Whitespace Remove whitespace (tabs, spaces and newlines) from any text. Try it free ](https://testingbot.com/free-online-tools/remove-all-whitespace) - [ ### Text to One Line Convert multi-line text or code into a single line without any breaks. Try it free ](https://testingbot.com/free-online-tools/text-to-one-line) ## Page Speed - [ ### Critical CSS Generator Speed up your website by preloading the critical CSS on your pages. Try it free ](https://testingbot.com/free-online-tools/critical-css-generator) ## Accessibility - [ ### Color Contrast Checker Check WCAG color contrast compliance for text and backgrounds. Try it free ](https://testingbot.com/free-online-tools/color-contrast-checker) ## Network Tools - [ ### What's My IP Address Find out your public IP address, location, ISP, and other network information instantly. Try it free ](https://testingbot.com/free-online-tools/whats-my-ip-address) - [ ### My GPS Location Get your current GPS coordinates from your browser with address lookup and map view. Try it free ](https://testingbot.com/free-online-tools/my-gps-location) - [ ### CORS Tester Test Cross-Origin Resource Sharing (CORS) configuration of any endpoint. Try it free ](https://testingbot.com/free-online-tools/cors-tester) ## Time & Date Tools - [ ### Unix Timestamp Converter Convert Unix timestamps to human-readable dates and get the current Unix timestamp. Try it free ](https://testingbot.com/free-online-tools/unix-timestamp-converter) - [ ### Cron Expression Generator Generate and test cron expressions with human-readable descriptions and next run times. Try it free ](https://testingbot.com/free-online-tools/cron-expression-generator) ## Converters - [ ### Puppeteer to Playwright Convert Puppeteer code into Playwright code. Try it free ](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [ ### PX to REM Converter Convert pixel values to REM units for responsive designs. Try it free ](https://testingbot.com/free-online-tools/px-to-rem-converter) ## Data Generators - [ ### Avatar Generator Generate random avatars for your projects and prototypes. Try it free ](https://testingbot.com/free-online-tools/free-avatar-generator) - [ ### Placeholder Image Generator Generate placeholder images with custom dimensions for your designs. Try it free ](https://testingbot.com/free-online-tools/placeholder-image-generator) - [ ### Credit Card Generator Generate fake credit card numbers online for testing. Try it free ](https://testingbot.com/free-online-tools/credit-card-number-generator) - [ ### Random Number Generator Generate a random number between any two numbers. Try it free ](https://testingbot.com/free-online-tools/random-number-generator) - [ ### JWT Parser Decode and parse JWT tokens to inspect their contents. Try it free ](https://testingbot.com/free-online-tools/jwt-parser) - [ ### Address Generator Generate a random postal address for testing. Try it free ](https://testingbot.com/free-online-tools/random-address-generator) - [ ### Fake Person Generator Generate details for a fake person for testing purposes. Try it free ](https://testingbot.com/free-online-tools/fake-person-generator) - [ ### Hash Text Hash text using MD5, SHA1, SHA256, SHA512, and more. Try it free ](https://testingbot.com/free-online-tools/hash-text) - [ ### Lorem Ipsum Generator Generate random placeholder text for your designs. Try it free ](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [ ### Random IP Generator Generate a random IPv4 address for testing. Try it free ](https://testingbot.com/free-online-tools/random-ip-generator) - [ ### GUID Generator Generate random and unique GUIDs. Try it free ](https://testingbot.com/free-online-tools/random-guid-generator) - [ ### Character Count Count the number of characters in any piece of text. Try it free ](https://testingbot.com/free-online-tools/character-count) - [ ### ASCII to Binary Convert ASCII text to its binary notation. Try it free ](https://testingbot.com/free-online-tools/ascii-to-binary) - [ ### Random Color Generator Generate random colors in HEX notation. Try it free ](https://testingbot.com/free-online-tools/random-color-generator) - [ ### Open Graph Meta Generator Generate OG and social media meta tags for your website. Try it free ](https://testingbot.com/free-online-tools/og-meta-generator) - [ ### QR Code Generator Generate and download QR codes with customizable options. Try it free ](https://testingbot.com/free-online-tools/qr-code-generator) - [ ### Device Information Get detailed info about your device, browser, and screen. Try it free ](https://testingbot.com/free-online-tools/device-information) - [ ### User Agent Parser Parse user agent strings to detect browser, OS, and device. Try it free ](https://testingbot.com/free-online-tools/user-agent-parser) - [ ### Image Extractor Extract all images from any public website. Try it free ](https://testingbot.com/free-online-tools/image-extractor) --- URL: https://testingbot.com/free-online-tools/html-escape [Tools](https://testingbot.com/free-online-tools)Code Formatter # HTML Escaper Escape special characters safely This generator escapes characters in HTML, allowing you to use HTML in other contexts such as in a `pre` tag. Characters such as `<` and `>` will be escaped. ### Enter Value ### Output ## What are the benefits of using HTML Escape Online? Escaping HTML characters is an essential practice in web development to ensure the security and integrity of web applications. When you escape HTML characters, you convert special characters into their respective HTML entities, preventing them from being interpreted as HTML code and avoiding potential security vulnerabilities. Here are the main benefits of escaping HTML characters: - **Preventing Cross-Site Scripting (XSS) Attacks**: XSS attacks occur when malicious code is injected into a web page and executed in the context of a user's browser. By escaping HTML characters, you prevent user input from being treated as code, effectively neutralizing XSS vulnerabilities. - **Avoiding Broken Layouts** : If unescaped HTML characters are inserted into a web page, they can disrupt the layout and structure of the page. Escaping characters prevents these rendering issues. - **Safe Rendering of User Input** : Escaping HTML characters allows developers to safely render user-generated content, such as comments or forum posts, without the risk of executing potentially harmful scripts. ## How to escape HTML in JavaScript? You can escape HTML in Javascript by replacing various characters from the input string, such as seen in the example below. const escapeHtml = (unsafe) => { return unsafe.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>') .replaceAll('"', '"').replaceAll("'", '''); }; const unsafeString = 'Hello & welcome!'; const safeString = escapeHtml(unsafeString); console.log(safeString); // Output:
Hello & welcome!
In this example, the `escapeHtml` function replaces special characters with their corresponding HTML entities. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/json-prettify [Tools](https://testingbot.com/free-online-tools)Code Formatter # JSON Prettifier Format and beautify JSON instantly To get started, please paste the JSON string in the first textarea. The second textarea will automatically generate the Prettified JSON. ### Enter Value ### Output JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate. It is often used for transmitting data between a server and a web application as an alternative to XML. JSON is based on a subset of the JavaScript programming language and consists of key-value pairs. ## What is Prettify JSON? Prettify JSON is a term used to describe the process of formatting a JSON string in a more human-readable and well-organized way. JSON strings can sometimes be long, compact, and difficult to read, especially when they contain nested objects or arrays. When you prettify JSON, you format the JSON string with proper indentation, line breaks, and whitespace, making it easier for humans to understand and navigate. This formatting does not affect the data itself; it only changes the presentation of the JSON string for better readability. ## What is JSON pretty format? JSON pretty format refers to the well-structured, human-readable representation of a JSON string with proper indentation, line breaks, and whitespace. When a JSON string is formatted in a pretty format, it becomes easier for humans to read and understand the data it contains, especially when dealing with complex JSON objects. The pretty format does not alter the data itself; it only changes the presentation of the JSON string for better readability. The goal is to make the JSON string more visually appealing and organized, which can be particularly helpful when working with large or nested JSON structures. ## How to prettify JSON in JavaScript? To prettify JSON in JavaScript, you can use the built-in `JSON.stringify()` method with the optional space parameter. The space parameter specifies the indentation applied to the JSON string, allowing you to generate a human-readable, pretty format. Here's how you can do it: const prettyJson = JSON.stringify(jsonData, null, 2); ## How to resolve JSON parse error? Ensure that the JSON data is in a valid format with proper syntax. JSON data should have matching opening and closing brackets/braces, and all property names and string values should be enclosed in double quotes. Remove any trailing commas at the end of arrays or objects. Trailing commas are not allowed in JSON and can cause a parse error. Ensure that all values in the JSON are valid. JSON supports strings, numbers, booleans, null, arrays, and objects. If there are any invalid values, such as functions or undefined, remove or convert them to valid JSON values. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/xml-prettify [Tools](https://testingbot.com/free-online-tools)Code Formatter # XML Prettifier Format and beautify XML instantly Paste the XML in the textarea below. TestingBot will automatically prettify the XML and output it in the second textarea. ### Enter Value ### Output ## What is XML Prettify Tool? TestingBot offers a free tool to clean up and indent XML code. TestingBot will make sure the indentation of all XML code is correct. ## What are the benefits of using XML Prettify Online? Using XML prettify, or formatting XML in a human-readable and well-organized manner, offers several benefits that make working with XML documents easier and more efficient: - **Improved Readability** : Prettified XML is easier to read and understand, especially when dealing with complex XML structures. Proper indentation and line breaks make the hierarchy and nesting of elements and attributes clear, enhancing readability. - **Debugging and Troubleshooting** : Prettified XML helps developers quickly identify issues and errors in the XML code. When an error occurs, it becomes easier to pinpoint the problematic section, allowing for faster debugging and troubleshooting. - **Version Control** : When using version control systems like Git, prettified XML allows for cleaner and more informative changes in version history. This helps developers understand the evolution of the XML document over time. ## How to prettify XML in JavaScript? You can prettify XML in Javascript by using `DOMParser()` and `XSLTProcessor`, see the example below: const prettifyXml = function(sourceXml) { const xmlDoc = new DOMParser().parseFromString(sourceXml, 'application/xml'); const xsltDoc = new DOMParser().parseFromString([ // describes how we want to modify the XML - indent everything '', ' ', ' ', // change to just text() to strip space in text nodes ' ', ' ', ' ', ' ', ' ', ' ', '', ].join('\n'), 'application/xml'); var xsltProcessor = new XSLTProcessor(); xsltProcessor.importStylesheet(xsltDoc); var resultDoc = xsltProcessor.transformToDocument(xmlDoc); var resultXml = new XMLSerializer().serializeToString(resultDoc); return resultXml; } ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/credit-card-number-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Credit Card Generator Create valid test card numbers Generate fake Credit Card numbers with this online generator tool. You can use these valid credit card numbers in your automated tests, to test payment flows and payment checkouts. **Credit Card Number** A credit card number generator is a software tool that employs coding techniques to simulate random credit card numbers. Developers and testers utilize this tool to evaluate the functionality of web pages without resorting to actual credit card information. These generators apply Luhn's algorithm to produce credit card numbers and associated details. These mock details are then employed as test data when crafting test scripts for web pages. Additionally, individuals can utilize this tool to generate fictitious credit card numbers for online forms, aiding in the testing of credit card processing systems. ## Use Our API to Generate Test Credit Card Numbers Developers can now integrate our fake credit card number generator directly into their applications or test suites via our public API. This is ideal for automated testing, QA environments and mock data generation. GET `https://api.testingbot.com/v1/free-tools/fake-credit-card` Response: { "credit_card_number": "4929429829012934" } The API returns a Luhn-valid fake credit card number in JSON format. You can call this endpoint programmatically to fetch a fresh test number each time. No authentication required. ## What is the mechanism behind a credit card number generator? - The **Major Identity Identifier** (MII) denotes the initial digit of the credit card number, signifying the category of the credit card provider. When using our credit card number generator tool, you can expect precise MII representation. - The **Issuer Identification Number** (IIN) represents the first six digits of a credit card number. This segment serves the purpose of identifying the institution responsible for issuing the credit cards. - **Luhn's Algorithm** stands as a validation formula essential for verifying credit card numbers. The TestingBot generator tool leverages Luhn's Algorithm in its backend operations, ensuring the provisioning of authentic credit card numbers, suitable for use in test data with your automated tests. ## Why use a Credit Card Number Generator? - Test **payment checkout pages** : Considering the sensitive nature of credit card data and the necessity for testers and developers to employ them frequently during the evaluation of purchase pages or processes, it becomes unsafe to include genuine credit card details in test data. With a credit card number generator, a fake (simulated) credit card numbersclosely resembling an authentic one, makes sure for valid testing while keeping everything secure. - Some payment providers supply their own dummy credit card numbers for testing/validation. With our tool, you have access to additional numbers for testing. Our generator is capable of generating thousands of various Visa/American Express and other credit cards. - Perform payment gateway testing by inputting the generated credit card numbers, either manually or during an automated test. ## Is it legal to use the TestingBot Credit Card Generator? Yes, this is definitely legal as these credit card numbers look like real numbers but cannot actually be used to perform purchases. Please use the generated numbers only in tests, against apps that allow you to perform this type of testing. ## Are the generated credit card numbers safe to use for sensitive transactions? These generated credit card numbers are primarily designed for testing purposes. We do not recommend using these during any sensitive tests/transactions. ## Can I make purchases using these credit card details? It is not possible to use these for real purchases, as the data that our generator outputs lacks information for a valid payment, such as: - A proper expiration date of the card - The cardholder's name - CVV numbers ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/critical-css-generator [Tools](https://testingbot.com/free-online-tools)Page Speed # Critical CSS Generator Boost your page load speed instantly Critical CSS is the CSS required to render the above-the-fold content. By preloading this CSS before the larger CSS file, your webpage will load faster. Improve your performance score and Core Web Vitals like First Contentful Paint (FCP). This in turn improves customer satisfaction and SEO scores for your website. Enter URL: Wait time (ms): In case you need to wait longer for Javascript or animations Viewport dimensions:800x6001024x7681280x8001280x9601280x10241440x9001680x10501600x12001920x12001920x10802560x1440 ![Generating CSS](https://testingbot.com/assets/loading-0406eae1b17f4903931d9817122fdfbe585651d8fb63e564cf9def4c609fb9f7.gif)Output:/\* Critical CSS will appear here \*/ This Critical CSS generator reduces render-blocking resources, minimizes bandwidth usage, and ensures faster perceived load times. The result is quicker page rendering and improved performance, vital for retaining visitors and boosting conversions. The generator is simple to use. You can use it for each of the webpages that you would like to optimize. Once added, your Pagespeed Insight metrics will improve drastically. ## Why should I use a Critical CSS Generator? CSS stylesheets block the rendering of pages. Pages might remain blank until the browser completes requesting, downloading, and parsing all stylesheets. To boost rendering of pages, minimizing the CSS load is crucial. Manually identifying critical CSS can be laborious. This generator streamlines the process by automating the identification of essential CSS. From an SEO perspective, quicker page loading times are crucial for search engine rankings. Google's algorithm prioritizes fast-loading websites, considering them more user-friendly. By optimizing Critical CSS, you create a streamlined browsing experience, signaling search engines that your site is responsive and valuable. Improved pagespeed contributes to lower bounce rates, longer user sessions, and ultimately, a positive impact on your SEO efforts. ## How do I add the Critical CSS generated to my webpage? Once you've generated the critical CSS for your page, you can add it to our webpage. See the example below on how to do this.
Hello, world!
In the above example, you would put your critical CSS in the head section of the DOM. The other css files will appear in the body, which means they will be loaded later in the webpage lifecycle. By loading the critical CSS in the head of the page, all DOM elements located before the large css files will use the critical CSS at the start of the webpage rendering process. ## Does this work for mobile websites as well? If you have a responsive website, generating the critical CSS with our tool will also work on mobile devices. You will notice improved pagespeed scores on mobile devices. ## Does this tool remove unused CSS? It will not remove unused CSS. This tool will check your webpage and see what CSS is required to display the above the fold content of your page. This CSS can be added to the page before the other (larger) CSS file, resulting in faster rendering of your webpages. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/random-ip-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Random IP Generator Generate valid IPv4 addresses Generate random IP addresses, to be used in your tests, for free with this online IP generator. These are valid IPs that can be used for testing your website or mobile app. ## Random IP Generator Generated IP Address ## What is a Random IP Generator? A random IP address generator will create valid looking, random IP addresses, which can be used in your tests (automated or manual). If your test, or the website/mobile app you are testing, requires a valid IP address, you can use this tool to create dummy IPs. ## Why do I need an IP Address Generator? The generator will generate a valid, public IP address. This IP address can be used in your automated or manual tests when required by the website or mobile app you are testing. ## What is the difference between an IPv4 and IPv6 address? The IPv4 address is the original format of an IP address and is still used by over 90% of all internet appliances. It consists of a 32-bit binary number, separated by dots. An IPv6 address is an 128-bit binary number, separated by colons. As it is 128 bit, the number of possibilities is exponentially bigger than the original IPv4 address. ## How do I generate an IP address in my test cases? This depends on the programming language you are using. An example on how to do this with Javascript or NodeJS can be found below. const randomIp = Array(4).fill(0).map((_, i) => Math.floor(Math.random() * 255) + (i === 0 ? 1 : 0)).join('.'); ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/random-address-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Address Generator Generate realistic test addresses Use this free tool to generate random addresses for a specific country. You can use this in your automated or manual tests, for example to fill in a form. ## Random Address Generator CountryGermanyAustraliaCanadaUnited StatesArgentinaSpainMexicoFranceIndonesiaItalyBelgiumNetherlandsPolandPortugal Generated Address ## Random Address Generator API Use our API to generate realistic random addresses for various countries. These addresses are useful for testing forms, filling mock user data, or populating QA environments with location-based content. GET `https://api.testingbot.com/v1/free-tools/random-address` Optional query parameter: - `?country=fr` — generate address using country (e.g., `us`, `au`, `fr`, `pl`, etc.) Response: { "address": "2436 Main Street, Springfield, IL 62704, United States" } ### Supported countries - `de` — Germany - `us` — United States - `ca` — Canada - `es` — Spain - `fr` — France - `id` — Indonesia - `it` — Italy - `nl` — Netherlands - `pl` — Poland - `pt` — Portugal This endpoint returns a randomly generated address in a format appropriate for the selected country. It is suitable for form-filling simulations, address validation testing or automated UI flows. ## What is a Random Address Generator? A Random Address Generator will generate fake, randomly created postal addresses. These are not real addresses, they do not exist, which means they cannot be used in production applications. Instead, these generated addresses are used for testing mobile applications or websites, which require the input of a valid looking postal address. ## Why do I need an Address Generator? You can use this generator to create valid looking, random postal addresses. Our address generator allows you to specify the country, after which the tool will generate a new (but fake) address. During your manual or automated tests, you can use this to generate addresses which can be used for your tests. For example, with a form that requires a postal address. ## How does this random address generator work? We use an utility called Faker. This program will generate fake data, that looks like it's real data. Under the hood, Faker will generate data such as random addresses. You can use this yourself with NodeJS and Ruby as well. ## How do I generate a fake address with Faker and Ruby? Once you've installed the Faker gem, you can simply call one function to generate an address. Please see the example below. Faker::Address.full_address ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/fake-person-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Fake Person Generator Create realistic test identities Use this free tool to generate fake person details, including a name, address and social security number. You can use this in your automated or manual tests, for example to fill in a form requesting personal details. ## Random Person Generator CountryGermanyAustraliaCanadaUnited StatesArgentinaSpainMexicoFranceIndonesiaItalyBelgiumNetherlandsPolandPortugal ## What is a Random Person Generator? A Random Person Generator will generate a fake, randomly created person with their full details. These are not real personal details, they do not exist, which means they cannot be used in production applications for testing. These generated personal details are used for testing mobile applications or websites, which require the input of valid looking personal details, such as an address, birthday, gender, phone number and more. ## Why do I need an Person Generator? You can use this generator to create valid looking but random personal details. Our person generator allows you to specify the country, after which the tool will generate a new (but fake) person. You can use this generated information in your tests, for example to test a form that requires the input of a person's details. ## How does this random people generator work? We use an utility called Faker. This is a tool that will generate fake data, but looks like it's real data. Under the hood, Faker will generate data such as random personal details. You can use this tool yourself with NodeJS and Ruby as well. ## How do I generate a fake person with Faker and Ruby? Once you've installed the Faker gem, you can use various functions to generate the necessary information. Please see the example below. name = Faker::Name.name address = Faker::Address.full_address ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/remove-all-whitespace [Tools](https://testingbot.com/free-online-tools)Code Formatter # Whitespace Remover Clean up text in seconds This tool will remove all the whitespace from the text you enter in the box below. Tabs, spaces, newlines will be removed. You will receive a spaceless string back. ## Remove Whitespace Tool Enter text: Welcome to the online whitespace, tab and newline remover tool. This web-based tool is built to remove all spaces from an input. The generator is simple to use. Simply enter the text (with spaces) in the textarea above, click the button and you will receive the same text back, but without any newlines, spaces or tabs. ## Why should I strip whitespaces from a piece of text? Automated tests often involve comparing actual program output or data with expected results. If your expected results contain extra whitespaces, tabs, or newlines, these inconsistencies can lead to test failures, even if the program's functionality is correct. Stripping whitespaces from expected results ensures that your tests are more precise and that they focus on functionality rather than formatting. ## How can I strip whitespaces using Javascript? You can use this oneliner Javascript code to remove all whitespaces, tabs and newlines from a string: return input.replace(/\s/g, '') ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/random-number-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Random Number Generator Generate numbers in any range If you are looking to generate random numbers with a simple to use tool, then you've found it with this Free Number Generator. Simply fill in a minimum and maximum value, the generator will randomly pick a number between these two values. ## Random Number Generator Minimum Maximum Random Number ## What is a Random Number Generator? A random number generator (RNG) will generate unique, non-repeating numbers between two values that you specify. By default, it will output a random number between 0 and 100. By changing the minimum and maximum values, you can tweak the process. ## Why do I need a Random Number Generator? This generator might be useful when you need to test an input form where a number is required. To make sure you cover all test cases, you might want to make the number unique, to make sure it does not trigger any duplicate errors. Let's say you are testing a form that requires a house number. You might want to make sure that you are always including a random house number during the test. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/character-count [Tools](https://testingbot.com/free-online-tools)Data Generators # Character Counter Count characters and words This free online tool allows you to count the number of characters in a piece of text. **Enter any piece of text** Text Character Count ## What is a Character Counter? A character counter is a tool that will calculate how many characters there are in a piece of text. It does this by going over all the individual characters and incrementing a counter. ## Why do I need a Character Counter? You might need to know the count of characters during an automated test, to make certain assertions when validating a specific flow. For example, you might expect a website or mobile app to return a piece of text. Using the character counter, you can make sure the text has the right number of characters. ## How can I count the characters of a string with Javascript? You can use the `.length` property of any string with Javascript. This property will return the amount of characters in the given string. const myString = "this is a piece of text"; const characterCount = myString.length; ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/text-to-one-line [Tools](https://testingbot.com/free-online-tools)Code Formatter # Text to One Line Convert multi-line to single line This free tool allows you to turn multi-line text or code into a single line without any breaks. **Enter Multi-Line Text** Input Text Replace Line Break With a Space Remove Extra Whitespaces Output (Single Line) Copy ## What Is Text To One Line Tool? The Text to One Line tool is a free online utility that converts multi-line text or code into a single line format. It removes line breaks and newlines, optionally replacing them with spaces or simply concatenating the lines together. This tool is particularly useful for formatting code snippets, JSON data, or any text that needs to be converted to a single line for compatibility or storage purposes. ## What are the usecases for Text To One Line Tools? Text to One Line tools have several practical applications: - **Code Formatting:** Converting multi-line code snippets for inline usage or documentation - **JSON Processing:** Minifying JSON data for API calls or configuration files - **CSV Data:** Converting multi-line text fields for proper CSV formatting - **SQL Queries:** Formatting complex multi-line SQL statements for logging or embedding - **Configuration Files:** Converting multi-line configurations to single-line format for certain systems - **Testing:** Preparing test data that needs to be in single-line format for automated tests - **Data Migration:** Converting text data formats during database migrations ## How to use Text to One Line Tool? Using the Text to One Line tool is simple: 1. Paste or type your multi-line text into the input textarea 2. Choose your options: - **Replace Line Break With a Space:** Replaces line breaks with spaces instead of removing them entirely - **Remove Extra Whitespaces:** Removes multiple consecutive spaces and trims whitespace 3. Click the "Convert to One Line" button 4. The converted single-line text will appear in the output area 5. Use the "Copy" button to copy the result to your clipboard ## What are the Advantages of this Tool? The Text to One Line tool offers several advantages: - **Free to Use:** Completely free online tool with no registration required - **Instant Processing:** Real-time conversion with immediate results - **Flexible Options:** Choose between different formatting options for your specific needs - **Copy Functionality:** One-click copy to clipboard for easy use - **No File Upload:** Works directly with pasted text, ensuring privacy and security - **Cross-Platform:** Works on any device with a web browser - **Developer-Friendly:** Perfect for developers working with code, JSON, or configuration files - **Large Text Support:** Can handle substantial amounts of text efficiently - **Preserve Formatting Options:** Choose how to handle spaces and whitespace according to your needs ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/placeholder-image-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Placeholder Images Generate custom size placeholders Placeholder images are used by designers to visualize a design before the final image is obtained. **Generate Placeholder Image** Width (pixels) Height (pixels) Maximum dimensions: 2000x2000 pixels ### Image Preview ![Generated placeholder](https://testingbot.com) Data URL (Base64) Copy This data URL can be used directly in HTML img tags or CSS background-image properties. ## What is a Placeholder Image Generator? A Placeholder Image Generator is a tool that creates temporary images with specified dimensions for use in design mockups, development, and prototyping. These images typically display the dimensions (like "400x300") prominently and serve as visual placeholders until final images are ready. The generator creates base64-encoded data URLs that can be used directly in HTML, CSS, or any application that accepts image data without requiring external file storage. ## Why are Placeholder images used? Placeholder images serve several important purposes in design and development: - **Design Visualization:** Help designers and stakeholders visualize layouts before final content is available - **Development Testing:** Allow developers to test responsive designs and image handling without waiting for final assets - **Content Planning:** Provide visual representation of space allocation for future images in websites and applications - **Client Presentations:** Enable showing design concepts to clients without placeholder content distracting from the overall design - **Performance Testing:** Help test page load times and layout behavior with images of specific dimensions - **Template Creation:** Essential for creating reusable design templates and themes - **Prototyping:** Speed up the prototyping process by providing instant placeholder content ## How does the Placeholder Image Generator work? The Placeholder Image Generator works using HTML5 Canvas technology: 1. **Input Dimensions:** You specify the desired width and height for your placeholder image (up to 2000x2000 pixels) 2. **Canvas Creation:** The tool creates an HTML5 canvas element with your specified dimensions 3. **Image Rendering:** It draws a gray background and renders the dimensions text (e.g., "400x400") in the center using canvas drawing APIs 4. **Base64 Encoding:** The canvas content is converted to a base64-encoded PNG data URL using the toDataURL() method 5. **Output Generation:** The resulting data URL can be copied and used directly in your code without requiring external image files 6. **Preview Display:** The tool also shows a visual preview of the generated placeholder image for verification This process happens entirely in your browser, ensuring privacy and instant results without server uploads. ## Why do designers and developers use image placeholders? Designers and developers use image placeholders for several practical reasons: - **Workflow Efficiency:** Continue working on layouts and functionality without waiting for final images from clients or photographers - **Consistent Testing:** Test designs with images of exact dimensions needed, ensuring proper layout behavior - **Client Communication:** Show design concepts clearly without "Lorem Ipsum" style distractions - **Responsive Design:** Test how designs adapt across different screen sizes with consistently sized placeholder content - **Performance Optimization:** Test page loading and rendering performance with known image dimensions - **Template Development:** Create reusable themes and templates with properly sized placeholder areas - **Quality Control:** Ensure image containers and styling work correctly before final content integration - **Documentation:** Provide clear examples in style guides and documentation showing required image dimensions - **Agile Development:** Maintain development momentum in agile workflows where content may arrive iteratively ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/lorem-ipsum-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Lorem Ipsum Generator Create placeholder text instantly Welcome to the free online Lorem Ipsum Generator. This free tool generates random pieces of Lorem Ipsum text. Random Text ## What is a Lorem Ipsum Generator? A Lorem Ipsum generator is a tool which will generate random sentences or words. It is used when you need to type or enter text in an application or website, without it having to be real text. ## Why do I need a Lorem Ipsum Generator? You can use this generator to generate random pieces of text, which can be used during manual or automated testing. For example, when you need to fill in a form on a web-app, but you don't want to fill in real text (due to privacy reasons, or legal reasons). It is an easy way to provide a placeholder text, when the actual content of your webpage is not yet available. Instead of leaving the space blank, you can fill it up with random text, allowing designers and developers to make sure the layout looks correct. ## What does Lorem Ipsum mean? In both written and visual contexts, the expression "lorem ipsum" represents a placeholder text used to fill content gaps in documents. "Dolorem Ipsum", roughly translates to "pain itself" in Latin, serves as the linguistic origin of the "lorem ipsum" term. The first sentences of a Lorem generator are usually something like this: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." Because it is written in Latin, it does not distract developers or designers while creating a page, since most people don't know how to read Latin and assume it's gibberish. ## How can I generate Random Lorem Ipsum text with Ruby? The Faker gem on Ruby allows you to generate random pieces of text. Please see the example below on how to do this. require('faker') Faker::Lorem.paragraph(sentence_count: 20) ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter [Tools](https://testingbot.com/free-online-tools)Converters # Puppeteer to Playwright Convert test scripts automatically This free tool will automatically convert any Puppeteer script or test to a Playwright script. Enter Puppeteer code: Converted Playwright Code: This online tool is built for developers and QA. It will replace existing Puppeteer syntax with Playwright syntax. You can quickly convert your existing Puppeteer scripts to Playwright, without having to manually do the conversion yourself. ## Why should I migrate from Puppeteer scripts to Playwright scripts? There are multiple reasons why you would want to start using Playwright. One reason is that Playwright runs on non-chromium based browsers, such as Firefox. Another reason might be that you want to use a library or specific Playwright extension. While both are very similar in the features they offer and even the syntax, there are some subtle differences. Puppeteer uses the CDP protocol to instrument browsers, whereas Playwright uses its own, custom protocol. ## How can I manually convert Puppeteer code to Playwright code? #### Changing the required package First, you need to change the require of the Puppeteer package to Playwright. You'll need to replace the code below. const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); With a new require, requiring the Playwright package. const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); #### Cookies Puppeteer handles cookies at the page level, whereas with Playwright you need to manipulate cookies at the `BrowserContext` level. This means that these Puppeteer cookie functions: - `page.cookies([...urls])` - `page.deleteCookie(...cookies)` - `page.setCookie(...cookies)` will become these functions with Playwright: - `browserContext.cookies([urls])` - `browserContext.clearCookies()` - `browserContext.addCookies(cookies)` #### Viewport Puppeteer's `page.setViewport` becomes `page.setViewportSize` in Playwright. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/ascii-to-binary [Tools](https://testingbot.com/free-online-tools)Data Generators # ASCII to Binary Convert text to binary code Use this free online generator to convert ASCII text to Binary Notation. ASCII Binary Output This online tool is built for developers and QA. It allows you to convert ASCII text to its binary representation. You can quickly convert any ASCII text to binary without manual calculation. ## Why should I need to convert ASCII to binary? Converting ASCII (American Standard Code for Information Interchange) to binary is necessary in certain contexts for various reasons: - **Data Representation:** Binary is the fundamental language of computers. Converting ASCII to binary allows computers to process and store textual data as a sequence of binary digits (ones and zeroes). - **Data Transmission:** When transmitting data over a network, binary is often used to represent characters, numbers, and other information. - **Encryption and Encoding:** In cryptographic operations and data encoding techniques, converting text to binary is a common step. Binary representations often enable various encryption algorithms and encoding methods to secure and transmit data more effectively. ## How do I convert ASCII to binary manually? You can manually convert ASCII to binary by using a conversion table or formula. For each character, you can find its decimal value. Once you have the decimal value, you can convert it to binary. ## How can I convert ASCII to binary with JavaScript? You can use the `charCodeAt` method to convert a character to its binary value: const character = "a" const binary = character.charCodeAt(0).toString(2) ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/random-color-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Random Color Generator Generate HEX color codes This free online tool allows you to generate random colors, which can be used in your apps or tests. ## Random Color Generator Color Value ## What is a Random Color Generator? A Random Color Generator is a software tool or algorithm that generates random colors. You can use this generator to create colors which can be used in your automated test cases, for example as an input in a specific form. The generator on this page will create unique HEX based colors, which you can copy/paste into your test scripts. ## How can I generate random colors in my test scripts? You can use this simple code below in Javascript which will generate unique HEX colors each time you call this method. Math.floor(Math.random()*16777215).toString(16) ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/color-contrast-checker [Tools](https://testingbot.com/free-online-tools)Accessibility # Color Contrast Checker Check WCAG accessibility compliance Enter foreground/background colors to get WCAG accessibility compliance info. Ensure your text is readable for all users. ## WCAG Color Contrast Checker Foreground Color (Text) Background Color Sample Text PreviewThe quick brown fox jumps over the lazy dog.This shows how your color combination looks in different text sizes. ### Contrast Ratio 21:1 #### Normal Text WCAG AAPASS WCAG AAAPASS #### Large Text WCAG AAPASS WCAG AAAPASS #### WCAG Requirements **Normal Text:** - • AA: 4.5:1 minimum - • AAA: 7:1 minimum **Large Text (18pt+ or 14pt+ bold):** - • AA: 3:1 minimum - • AAA: 4.5:1 minimum Swap Colors ## What is color contrast? Color contrast refers to the difference in light between font (or anything in the foreground) and its background. In web accessibility, color contrast is a measure of the difference in perceived brightness between two colors. This difference is expressed as a ratio ranging from 1:1 (no contrast, same color) to 21:1 (maximum contrast, black on white or vice versa). The Web Content Accessibility Guidelines (WCAG) define specific contrast ratios to ensure text is readable for users with visual impairments, including color blindness and low vision conditions. Proper color contrast ensures that content is perceivable by the widest possible audience. ## Why is color contrast important for accessibility? Color contrast is crucial for web accessibility for several important reasons: - **Visual Impairments:** Approximately 285 million people worldwide have visual impairments. Sufficient contrast helps users with low vision, cataracts, or age-related vision loss read content more easily. - **Color Blindness:** About 8% of men and 0.5% of women have some form of color blindness. Good contrast ratios ensure content remains readable regardless of color perception differences. - **Environmental Factors:** Users may view content on devices in bright sunlight, on low-quality screens, or with glare, all of which reduce perceived contrast. - **Cognitive Load:** Better contrast reduces eye strain and cognitive load for all users, making content easier to read and understand. - **Legal Compliance:** Many countries require websites to meet WCAG standards, making proper contrast a legal requirement for public and commercial websites. ## How can I ensure proper color contrast in my designs? Follow these best practices to ensure your designs meet color contrast requirements: - **Test Early and Often:** Use this color contrast checker tool during the design phase, not after implementation. Test all text and important visual elements against their backgrounds. - **Follow WCAG Guidelines:** Aim for WCAG AA compliance at minimum (4.5:1 for normal text, 3:1 for large text). Consider AAA compliance (7:1 and 4.5:1 respectively) for critical content. - **Don't Rely on Color Alone:** Use additional indicators like underlines for links, icons, or text labels to convey information. - **Test with Real Users:** Conduct usability testing with users who have visual impairments to validate your contrast choices. - **Consider Different States:** Check contrast for all interactive states (hover, focus, active, disabled) and ensure they all meet requirements. - **Use Design Systems:** Create a color palette with pre-tested combinations that meet contrast requirements to ensure consistency across your project. ## What are WCAG contrast ratio requirements? The Web Content Accessibility Guidelines (WCAG) 2.1 define specific contrast ratio requirements for different levels of compliance: ### Level AA (Minimum Compliance) - **Normal Text:** Minimum contrast ratio of 4.5:1 - **Large Text:** Minimum contrast ratio of 3:1 - **Graphics & UI Components:** Minimum contrast ratio of 3:1 ### Level AAA (Enhanced Compliance) - **Normal Text:** Minimum contrast ratio of 7:1 - **Large Text:** Minimum contrast ratio of 4.5:1 **Note:** Large text is defined as 18pt (24px) or larger for regular weight, or 14pt (18.5px) or larger for bold weight. Level AAA is not required for entire websites but is recommended for critical content. ## How is the contrast ratio calculated? The contrast ratio is calculated using the relative luminance of the two colors according to the WCAG formula: Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) Where L1 is the relative luminance of the lighter color and L2 is the relative luminance of the darker color. The relative luminance is calculated by: 1. Converting RGB values to sRGB (values between 0 and 1) 2. Applying gamma correction to each channel 3. Calculating weighted sum: 0.2126 \* R + 0.7152 \* G + 0.0722 \* B This tool automatically performs these calculations for you, instantly showing whether your color combinations meet WCAG standards for both normal and large text sizes. ## What tools can help with color contrast testing? Several tools and techniques can help you test and ensure proper color contrast: - **This Color Contrast Checker:** Use our free tool above to test any color combination instantly against WCAG standards. - **Browser DevTools:** Chrome and Firefox DevTools include built-in contrast ratio checkers in their color pickers. - **Design Software Plugins:** Figma, Sketch, and Adobe XD have plugins like Stark or Able that check contrast ratios during design. - **Automated Testing:** Tools like axe DevTools, WAVE, or Lighthouse can scan entire pages for contrast issues. - **Manual Testing:** Use browser extensions like WCAG Color Contrast Checker or Colour Contrast Analyser (CCA) for on-page testing. - **Screen Readers:** Test with actual assistive technologies to understand the real user experience. Remember to test contrast in different contexts: on various devices, under different lighting conditions, and with different display settings to ensure accessibility for all users. ### All Tools #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/cors-tester [Tools](https://testingbot.com/free-online-tools)Network Tools # CORS Tester Test cross-origin configuration Test Cross-Origin Resource Sharing (CORS) configuration by sending a fetch request to any endpoint and checking if it passes or fails CORS validation. Endpoint URL HTTP Method GETPOSTPUTDELETEPATCHHEADOPTIONS Custom Headers (Optional) One per line, format: Header-Name: value Request Body (Optional) For POST, PUT, PATCH requests Test CORS ## ### Response Headers | Header | Value | | --- | --- | ### Response ## What is CORS? CORS (Cross-Origin Resource Sharing) is a security feature implemented by web browsers that controls how web pages from one domain can access resources from another domain. It's a mechanism that uses HTTP headers to tell browsers whether to allow a web application running at one origin to access selected resources from a server at a different origin. By default, browsers enforce the Same-Origin Policy, which blocks requests between different origins. CORS provides a controlled way to relax this restriction, allowing servers to specify which origins are permitted to access their resources. ## How to Enable CORS in Different Programming Languages? ### Node.js (Express) // Install cors package: npm install cors const cors = require('cors'); app.use(cors({ origin: 'https://example.com', credentials: true })); ### Python (Flask) # Install flask-cors: pip install flask-cors from flask_cors import CORS CORS(app, origins=['https://example.com']) ### Ruby on Rails # In config/initializers/cors.rb Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'example.com' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end ### PHP header("Access-Control-Allow-Origin: https://example.com"); header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE"); header("Access-Control-Allow-Headers: Content-Type"); ### Java (Spring Boot) @CrossOrigin(origins = "https://example.com") @RestController public class ApiController { // Your endpoints } ## What are CORS Preflight Requests? A CORS preflight request is an OPTIONS request that browsers automatically send before certain cross-origin requests. This happens when the request uses methods other than GET, HEAD, or POST, or when it includes custom headers. The preflight request checks with the server whether the actual request is allowed. The server responds with headers indicating which origins, methods, and headers are permitted. Only if the preflight succeeds will the browser send the actual request. Understanding preflight requests is crucial for debugging CORS issues, as failures in the preflight phase will prevent your actual request from being sent. ## Common CORS Error Messages and Solutions Error: "No 'Access-Control-Allow-Origin' header" Solution: The server needs to include the Access-Control-Allow-Origin header in its response. Configure your server to add this header with appropriate origin values. Error: "CORS header 'Access-Control-Allow-Origin' missing" Solution: Similar to above, ensure your server is configured to send CORS headers. Check that your server-side CORS configuration is properly set up. Error: "Credentials flag is true but Access-Control-Allow-Credentials is not 'true'" Solution: When sending credentials (cookies, auth headers), the server must include `Access-Control-Allow-Credentials: true` header, and `Access-Control-Allow-Origin` must not be a wildcard (\*). ## CORS Headers Explained - **Access-Control-Allow-Origin:** Specifies which origins can access the resource. Use specific domains for security, not wildcard (\*) in production. - **Access-Control-Allow-Methods:** Lists the HTTP methods allowed when accessing the resource (GET, POST, PUT, DELETE, etc.). - **Access-Control-Allow-Headers:** Indicates which headers can be used during the actual request. - **Access-Control-Allow-Credentials:** Indicates whether the response can be shared when credentials flag is true. - **Access-Control-Max-Age:** Indicates how long the results of a preflight request can be cached. - **Access-Control-Expose-Headers:** Lists headers that the browser can access from the response. ## How to Test CORS Configuration? Testing CORS configuration is essential to ensure your API is accessible from authorized origins while maintaining security. Use this CORS tester tool to: - Verify that your API endpoints are properly configured for cross-origin requests - Test different HTTP methods (GET, POST, PUT, DELETE) to ensure they're allowed - Check if custom headers are accepted by your server - Validate preflight request handling for complex requests - Debug CORS errors by examining response headers - Test authentication scenarios with credentials Regular CORS testing helps prevent issues in production and ensures smooth integration with frontend applications hosted on different domains. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/random-guid-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # GUID Generator Create unique identifiers This free online tool allows you to generate random GUID (Globally Unique Identifier) or UUIDs (Universally Unique Identifier). ## Random GUID Generator Number of GUIDs to generate Results ## What is a random GUID generator? You can easily generate Globally Unique Identifiers (GUIDs) with this Random GUID Generator. These uniquely identifying strings are generated locally using JavaScript within the online GUID generator, to make sure no data is transmitted over the internet. You can use GUID identifiers in programs or testcases. If you need to store an item or query a unique thing from a database, we recommend using GUIDs as these are unique strings that cannot be guessed. In contrast with auto-incremented identifiers, these identifiers are much more secure to use. ## Why use Random GUID Generator? Utilizing a Random GUID Generator offers several advantages and use cases: - **Global Uniqueness:** GUIDs (Globally Unique Identifiers) generated by a Random GUID Generator are designed to be globally unique. The randomization process significantly reduces the likelihood of duplication, ensuring that each generated identifier is highly distinctive. - **Security:** Random GUIDs enhance security by providing a level of unpredictability. The random nature of the generated identifiers makes it challenging for malicious entities to predict or manipulate them, contributing to improved security in various applications. - **Data privacy:** When using this online Random GUID Generator, the generation process loccurs locally in your browser. This means that the data used to create the GUIDs doesn't need to be transmitted over the internet, contributing to enhanced data privacy. - **Promo Code Generation:** Random GUIDs are often employed in e-commerce for generating unique promo codes. This ensures that each promotional code is distinct, reducing the risk of abuse or exploitation. You could for example use this as mock-data for a testcase that needs to test a coupon code in a shopping cart. ## How unique is a GUID? A GUID is designed to be extremely unique, but the degree of uniqueness is not absolute. GUIDs are 128-bit values and their uniqueness is primarily achieved through a combination of factors: - **Randomness:** Many modern GUIDs are generated using algorithms that incorporate random or pseudo-random components. This randomness contributes significantly to uniqueness, as the likelihood of two randomly generated GUIDs being identical is very low. - **Timestamps:** Some GUIDs include a timestamp component, which is a combination of the current time and the unique identifier of the computer or network card generating the GUID. This helps ensure uniqueness, especially when GUIDs are generated at different times, or generated on different machines. When high levels of uniqueness are required, additional measures, such as using GUIDs with timestamps or other unique elements, can be implemented. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/free-avatar-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Avatar Generator Generate realistic placeholder photos Quickly generate realistic avatar images using our free avatar API. Perfect for developers and designers who need dummy user photos for testing, mockups or placeholder content. These randomly generated avatars of people are ideal for use as sample profile pictures in web and mobile apps. ## Random Avatar Generator ## Random Avatar https://testingbot.com/free-online-tools/random-avatar/{size} Example [See](https://testingbot.com/free-online-tools/random-avatar/300) https://testingbot.com/free-online-tools/random-avatar/300 The maximum allowed size is 1000 ## Direct Image ID https://testingbot.com/free-online-tools/random-avatar/200?img=3 ## Unique ID https://testingbot.com/free-online-tools/random-avatar/200?u=fake@testingbot.com https://testingbot.com/free-online-tools/random-avatar/200?u=u837kfei139kn Add an identifier and you will always get the same image. ## What is a Random Avatar Generator? This free tool generates realistic avatar photos that can be used as placeholder images in your web or mobile projects. It's ideal for developers and designers who need dummy user photos for testing or mockups. ## How can I use the avatars in my project? You can use the avatars as user profile pictures during development or testing. Simply request the API with a desired image size or unique identifier to get a usable image URL. They're great for UI placeholders in apps, dashboards, signup forms or even in unit tests and functional tests. ## Can I generate the same avatar for each user? Yes. By passing a unique identifier such as a username, email, or user ID to the API, the generator will always return the same avatar for that ID. This makes it deterministic and ideal for consistent placeholder images across sessions. You can use the `u=` parameter in the URL to specify a unique identifier. For example, `https://testingbot.com/free-online-tools/random-avatar/128?u=12345` will always return the same avatar for the ID 12345, with an avatar dimension of 128x128 pixels. ## Is it free to use the avatar API? Yes, this avatar generator is completely free to use with no registration required. You can request as many avatar images as needed for your development or testing environment. ## What sizes are supported by the API? You can request avatar images in any square dimension by specifying the size in the URL, such as `https://testingbot.com/free-online-tools/random-avatar/128` or `https://testingbot.com/free-online-tools/random-avatar/512`. The image will be returned at that width and height. The maximum allowed dimension is 1000 pixels. If you request a size larger than that, the service will return an image of 1000x1000 pixels. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/hash-text [Tools](https://testingbot.com/free-online-tools)Data Generators # Hash Text Generate MD5, SHA and more This free online hash text generator will convert the text that you input to various hashes, with a specific Digest encoding. Start typing to see the various hashes, ranging from SHA1 to SHA256, MD5 and RIPEMD160. ## Hash Text Generator Your text to hash: Digest encodingBase64 (base 64)Binary (base 2)Hexadecimal (base 16) | Algorithm | Hash Output | | --- | --- | | MD5 | | | SHA1 | | | SHA256 | | | SHA224 | | | SHA512 | | | SHA384 | | | SHA3 | | | RIPEMD160 | | ## What is a Hash Text Generator? A Hash Text Generator is a tool that takes an input string (text) and computes a cryptographic hash of that string using a specified hash algorithm. The output is a fixed-size string of characters, which appears random and is typically used for data integrity verification, password storage or as a unique identifier for data. Common hash algorithms include MD5, SHA1, SHA256, SHA512, and others. The generated hash is deterministic, which means the same input will always produce the same hash output. ## Why do I need a Hash Text Generator? A Hash Text Generator is useful for various purposes: - **Data Integrity Verification** : By comparing hash values, you can verify that data has not been altered or corrupted during transmission or storage. - **Unique Identifiers** : Hashes can serve as unique identifiers for files or data blocks, useful in scenarios like deduplication or cache keys. - **Testing and Development** : Developers and QA engineers can use a Hash Text Generator to create test cases, verify hashing algorithms or ensure that applications handle hash values correctly. Hashes can be used to verify data integrity across different environments and browsers. ## How is a hash text generator built? A Hash Text Generator is typically built using cryptographic hash functions provided by programming languages or libraries. In JavaScript, for instance, you can use the Web Crypto API for modern browsers or external libraries like CryptoJS for broader compatibility. The basic steps to build a hash text generator include: 1. **Input Handling** : Capture the text input from the user interface. 2. **Algorithm Selection** : Allow the user to select which hash algorithm to use (e.g., MD5, SHA1, SHA256). 3. **Hash Computation** : Use the selected algorithm to compute the hash of the input text. 4. **Digest Encoding** : Convert the hash output into a human-readable format, such as hexadecimal, base64, or binary encoding. 5. **Display Output** : Present the computed hash to the user. ## What are common use cases for a hash text generator in automated testing? In automated testing, a hash text generator can be used to: - **Verify Data Consistency** : By hashing outputs from different environments or browsers, testers can ensure that the data remains consistent across platforms. - **Detect Changes** : Hashes can detect even minor changes in data output, which is helpful when verifying that applications behave identically across different browsers during cross-browser testing on platforms like TestingBot. - **Security Testing** : Testing the implementation of hashing functions in applications, ensuring that passwords and sensitive data are hashed correctly before storage or transmission. - **Performance Benchmarking** : Comparing the performance of hashing algorithms across different devices and browsers. ## How does a hash function work? A hash function takes input data of arbitrary size and produces a fixed-size string of characters, which is typically a digest that represents the input data uniquely. Cryptographic hash functions are designed to be one-way functions, meaning it is computationally infeasible to reverse the output back to the original input. They are also designed so that small changes in the input produce significantly different outputs, a property known as the avalanche effect. ## What are the differences between MD5, SHA1, SHA256 and other hash algorithms? The primary differences between these hash algorithms are their output size and security levels: - **MD5** : Produces a 128-bit hash value. It is fast but considered cryptographically broken due to vulnerabilities that allow for hash collisions. - **SHA1** : Produces a 160-bit hash value. It has been deprecated for use in security-critical applications because of known vulnerabilities. - **SHA256** : Part of the SHA-2 family, it produces a 256-bit hash value and is considered secure for most applications. - **SHA3** : The latest standard, designed to be secure against attacks that may affect SHA-2. - **RIPEMD160** : Produces a 160-bit hash value, similar to SHA1, but with a different design. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/jwt-parser [Tools](https://testingbot.com/free-online-tools)Data Generators # JWT Parser Decode and inspect JWT tokens This online JWT parser will display all the values embedded in the JWT token. This can be useful to investigate issues with JWT tokens used in web apps. Enter your JWT token: ## Header | Parameter | Value | | --- | --- | ## Payload | Claim | Value | | --- | --- | ## What is a JWT Parser? A JWT Parser is a tool that takes a JSON Web Token (JWT) as input and decodes it to reveal the contents of the header and payload sections. JWTs are encoded in Base64url format and consist of three parts: header, payload and signature. Parsing a JWT allows developers and testers to inspect the claims and metadata contained within the token without validating the signature. ## When should I use a JWT Parser? You should use a JWT Parser when you need to examine the contents of a JWT, such as during development, debugging or testing of authentication and authorization mechanisms in web applications and APIs. It helps in verifying that the correct claims are included, that they have the expected values and that the token is structured properly. This is particularly useful for developers and QA engineers performing automated tests on platforms like TestingBot, where ensuring correct token generation and handling across different browsers and devices is essential. ## How can a JWT Parser help with automated testing? A JWT Parser can assist in automated testing by allowing test scripts to programmatically inspect and validate the contents of JWTs generated by an application. This ensures that the tokens contain the correct claims and that sensitive information is not unintentionally exposed. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/px-to-rem-converter [Tools](https://testingbot.com/free-online-tools)Converters # PX to REM Converter Make your CSS responsive When designing modern web pages, switching from fixed pixel values (PX) to relative units like REM ensures your content adapts seamlessly across various devices and screen sizes. With just a few clicks, you can convert pixel values to REM units, making your design more flexible and accessible. ## PX to REM Converter Base size in px EM em Pixel px Rem rem Percentage % Point pt Values update automatically as you type ## What is the PX to REM Converter? The PX to REM Converter is a free online tool that helps web developers and designers convert pixel (PX) values to REM units. REM units are relative to the root element's font size, making them ideal for creating responsive and accessible web designs that scale properly across different devices and user preferences. This converter supports bidirectional conversion, allowing you to convert from pixels to REM or from REM to pixels, along with other related CSS units like EM, percentages, and points. ## Use Cases of the PX to REM Converter Tool - **Font Size Conversion:** Convert fixed pixel font sizes to scalable REM units for better accessibility - **Spacing and Margins:** Transform pixel-based spacing into responsive REM values for consistent layouts - **Component Design:** Ensure UI components scale properly across different screen sizes and user settings - **Legacy Code Migration:** Modernize existing CSS by converting pixel values to more flexible REM units - **Design System Implementation:** Establish consistent spacing and typography scales using REM values - **Accessibility Compliance:** Support users who adjust their browser's default font size for better readability ## What is the Difference Between PX and REM? **Pixels (PX):** Absolute units that represent a fixed size on the screen. 1px is always 1px regardless of the user's settings or device characteristics. While precise, pixels don't adapt to user preferences or different viewing contexts. **REM:** Relative units based on the root element's font size (typically 16px in most browsers). 1rem equals the root font size, so if a user increases their browser's font size, REM values scale proportionally, making content more accessible and responsive. The key advantage of REM is that it respects user preferences and creates more flexible, accessible designs that work well across different devices and accessibility needs. ## How to Use TestingBot's PX to REM Converter ### 1. Set the Root Font Size Enter your website's base font size in the "Base size in px" field. The default is 16px, which is the standard browser default. ### 2. Identify the PX Values You Want to Convert Look through your CSS for pixel values that you want to make more responsive, such as font sizes, margins, or padding. ### 3. Input Values into the Converter Enter your pixel values in the "Pixel" field, or REM values in the "Rem" field. The converter automatically calculates the equivalent values in real-time. ### 4. Replace PX with REM in Your CSS Copy the converted REM values and update your CSS files, replacing the fixed pixel values with the responsive REM equivalents. ### 5. Test for Browser Compatibility and Scaling Test your website by changing the browser's default font size to ensure your design scales properly and remains visually appealing. ## Is converting to REM necessary for responsive design? While not strictly necessary, converting to REM units significantly improves responsive design and accessibility. REM units automatically adapt to user preferences and different viewing contexts, making your website more inclusive and user-friendly. Modern web development best practices recommend using relative units like REM for better scalability and accessibility compliance. ## What's the default root font size in browsers? Most browsers use 16px as the default root font size. This means 1rem equals 16px by default. However, users can change this setting in their browser preferences, which is why using REM units is beneficial - your design will automatically adapt to these user preferences. ## When should I use REM instead of PX? Use REM for: - Font sizes and typography - Spacing (margins, padding) - Component dimensions that should scale with text - Any measurement that benefits from user accessibility settings Continue using PX for: - Border widths (1px borders) - Small decorative elements - Elements that must remain fixed regardless of font size ## Can I use both PX and REM in the same stylesheet? Yes, absolutely! It's common and recommended to use both PX and REM units in the same stylesheet. Use each unit where it makes the most sense - REM for scalable elements and PX for fixed elements. This hybrid approach gives you the flexibility of responsive design while maintaining precise control where needed. ## What does the PX to REM Converter do? The PX to REM Converter calculates the equivalent REM value for any given pixel measurement based on your specified root font size. It performs the simple calculation: REM = Pixels ÷ Root Font Size. The tool also provides conversions to related units like EM, percentages, and points, making it a comprehensive solution for CSS unit conversion. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/og-meta-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # Open Graph Generator Create social media meta tags Generate open-graph and social media HTML meta tags for your website. Optimize how your content appears when shared on Facebook, Twitter, LinkedIn and other social platforms. Page TypeWebsiteArticleProductProfileBookMusicVideo Page URL Title Description Image URL Image Alt Text Image Width (px) Image Height (px) ### Generated Meta Tags Copy to Clipboard ## What are Open Graph meta tags? Open Graph meta tags are HTML meta elements that control how URLs are displayed when shared on social media platforms like Facebook, Twitter, LinkedIn, and others. These tags provide structured data about your webpage, including the title, description, image, and type of content. When you share a link on social media, the platform uses these Open Graph tags to create an attractive preview card with an image, title, and description. This greatly improves engagement and click-through rates compared to plain text links. ## What are the essential Open Graph meta tags? The four essential Open Graph meta tags that every webpage should have are: - **og:title** - The title of your page as it should appear in social media - **og:description** - A brief description of the page content - **og:image** - The URL to an image that represents your page - **og:url** - The canonical URL of your page Additionally, `og:type` helps specify the type of content (website, article, product, etc.) and `og:site_name` identifies your website or brand name. ## What image dimensions work best for Open Graph images? The recommended dimensions for Open Graph images are **1200x630 pixels** (1.91:1 aspect ratio). This size works optimally across all major social media platforms including Facebook, Twitter, LinkedIn, and others. - Minimum recommended size: 600x314 pixels - Maximum file size: Generally under 5MB for best performance - Supported formats: JPG, PNG, WebP, and GIF - Avoid images with too much text, as they may be penalized by some platforms ## How do I test my Open Graph meta tags? You can test your Open Graph meta tags using several free debugging tools: - **Facebook Sharing Debugger** - Official tool from Facebook to preview and debug Open Graph tags - **Twitter Card Validator** - Twitter's tool for validating Twitter Card meta tags - **LinkedIn Post Inspector** - LinkedIn's tool for previewing how posts will appear - **Open Graph Check** - Third-party tools that validate multiple platforms at once These tools will show you exactly how your page will appear when shared and highlight any missing or problematic tags. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/qr-code-generator [Tools](https://testingbot.com/free-online-tools)Data Generators # QR Code Generator Create scannable QR codes Generate and download QR codes for URLs, text, or any content. Customize colors and error correction levels for optimal scanning performance. Text or URL Foreground Color Background Color Error Correction LevelLow (~7%)Medium (~15%)Quartile (~25%)High (~30%) Higher levels allow the QR code to be read even if partially damaged or obscured. ### Generated QR Code Download QR Code ## What is a QR Code? A QR Code (Quick Response Code) is a two-dimensional barcode that can store various types of information such as text, URLs, phone numbers, or other data. QR codes can be quickly scanned by smartphones, tablets, and dedicated QR code readers to instantly access the encoded information. Originally developed in 1994 for tracking automotive parts, QR codes have become widely used for marketing, payments, authentication, and information sharing due to their fast readability and large storage capacity compared to traditional barcodes. ## What can I encode in a QR Code? QR codes can encode various types of data including: - **URLs and Websites** - Direct users to web pages, social media profiles, or online content - **Plain Text** - Any text information, messages, or instructions - **Contact Information** - Phone numbers, email addresses, or vCard data - **WiFi Credentials** - Network name and password for easy connection - **SMS Messages** - Pre-filled text messages with recipient numbers - **Email Addresses** - mailto links with optional subject and body text - **Geographic Locations** - GPS coordinates or addresses for mapping applications ## What do the error correction levels mean? Error correction levels determine how much of the QR code can be damaged or obscured while still remaining readable: - **Low (L)** - Can recover from about 7% damage. Best for clean, controlled environments. - **Medium (M)** - Can recover from about 15% damage. Good balance for most applications. - **Quartile (Q)** - Can recover from about 25% damage. Better for outdoor or rough handling. - **High (H)** - Can recover from about 30% damage. Best for harsh environments or when partial obscuring is likely. Higher error correction levels create larger QR codes with more data redundancy, so choose the level that best matches your intended use case. ## How do I scan a QR Code? Most modern smartphones can scan QR codes without additional apps: - **iPhone (iOS 11+)** - Open the Camera app and point it at the QR code. A notification will appear with the content. - **Android** - Open the Camera app or Google Assistant, point at the QR code. Many Android phones have built-in QR scanning in their camera apps. - **Dedicated Apps** - Download QR code scanner apps from app stores for additional features like scan history and batch processing. - **Web Browsers** - Some browsers like Chrome and Edge have built-in QR code scanning capabilities. For best scanning results, ensure good lighting, hold the device steady, and position the QR code within the camera's viewfinder. ## What are the best practices for QR Code design? Follow these best practices to ensure your QR codes scan reliably: - **Contrast** - Use high contrast between foreground and background colors (dark on light works best) - **Size** - Minimum size of 2x2 cm (0.8x0.8 inches) for print, larger for distance scanning - **Quiet Zone** - Leave white space around the QR code (at least 4 modules wide) - **Testing** - Always test your QR codes on multiple devices before deploying - **Content Length** - Shorter content creates simpler, more scannable QR codes - **Print Quality** - Use high-resolution images for printing to avoid pixelation ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/device-information [Tools](https://testingbot.com/free-online-tools)Data Generators # Device Information Detect browser and system details Get comprehensive information about your device, browser, screen resolution, operating system, and capabilities. Perfect for testing and development. ## Browser Information Browser Name Detecting... Browser Version Detecting... Browser Engine Detecting... JavaScript Enabled Yes Cookies Enabled Detecting... Local Storage Detecting... User Agent Detecting... ## Operating System Operating System Detecting... Platform Detecting... Architecture Detecting... CPU Cores Detecting... Memory (Approx) Detecting... Device Type Detecting... ## Screen & Display Screen Resolution Detecting... Available Resolution Detecting... Browser Window Size Detecting... Viewport Size Detecting... Color Depth Detecting... Pixel Ratio Detecting... Orientation Detecting... Touch Support Detecting... ## Network & Connection Connection Type Detecting... Effective Type Detecting... Downlink Speed Detecting... RTT (Ping) Detecting... Online Status Detecting... Do Not Track Detecting... ## Browser Capabilities WebGL Support Detecting... WebRTC Support Detecting... Geolocation API Detecting... Service Worker Detecting... WebSocket Support Detecting... IndexedDB Support Detecting... Canvas Support Detecting... WebAssembly Detecting... ## Languages & Time Languages Detecting... Timezone Detecting... Current Time Detecting... UTC Offset Detecting... ## What information can this tool detect about my device? This device information tool can detect a wide range of details about your system including: - **Browser Information** - Name, version, engine, user agent, and capabilities - **Operating System** - OS name, platform, architecture, CPU cores, and memory - **Screen Details** - Resolution, color depth, pixel ratio, and orientation - **Network Information** - Connection type, speed, and online status - **Supported Technologies** - WebGL, WebRTC, Canvas, WebAssembly support - **Language & Time** - Browser languages, timezone, and current time ## Why would I need to check my device information? Checking device information is useful for several purposes: - **Web Development** - Testing how your website appears on different devices and browsers - **Troubleshooting** - Identifying browser compatibility issues or missing features - **System Diagnostics** - Checking if your browser supports modern web technologies - **Privacy Awareness** - Understanding what information websites can detect about you - **Technical Support** - Providing detailed system information when reporting issues - **Performance Testing** - Understanding device capabilities for optimization ## How accurate is browser and device detection? Device detection accuracy varies depending on the type of information being detected: - **Highly Accurate** - Screen resolution, browser capabilities, JavaScript/cookie support - **Generally Accurate** - Browser name/version, basic OS detection, language preferences - **Approximate** - Device memory, CPU cores (limited by browser security policies) - **May Be Blocked** - Geolocation, device orientation (requires user permission) Some information may be limited or blocked by privacy settings, browser extensions, or security policies. Modern browsers intentionally limit certain device fingerprinting capabilities to protect user privacy. ## Can websites track me using this device information? While device information can be used for tracking, there are important privacy considerations: - **Browser Fingerprinting** - Combinations of device characteristics can create unique identifiers - **Privacy Protection** - Modern browsers limit access to sensitive device information - **User Control** - You can disable JavaScript, use privacy extensions, or browse in incognito mode - **Legitimate Uses** - Most websites use device info for optimization and compatibility, not tracking To enhance privacy, consider using browser privacy settings, VPNs, or privacy-focused browsers that limit device fingerprinting capabilities. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/user-agent-parser [Tools](https://testingbot.com/free-online-tools)Data Generators # User Agent Parser Analyze browser user agents Analyze and parse user agent strings to extract detailed information about browsers, engines, operating systems, CPU architecture, and devices. ## User Agent String Enter or paste a user agent string to analyze: Your current user agent is automatically loaded Parse User Agent ## Browser Name - Version - Major Version - ## Engine Name - Version - ## Operating System Name - Version - ## Device Type - Model - Vendor - ## CPU Architecture - ## Top 10 Most Popular User Agents (2026) | Browser | OS | Device | Action | | --- | --- | --- | --- | ## What is a User Agent? A User Agent is a string of text that web browsers and applications send to web servers to identify themselves. It contains crucial information about the browser name, version, operating system, device type, and rendering engine being used. This identification helps web servers deliver optimized content for specific browsers and devices. The User Agent string follows a semi-standardized format but can vary significantly between browsers. It typically includes: - Browser name and version (e.g., Chrome/120.0.0.0) - Operating system information (e.g., Windows NT 10.0) - Rendering engine details (e.g., Gecko, WebKit, Blink) - Device information for mobile devices - Additional compatibility tokens Understanding User Agent strings is essential for web development, browser compatibility testing, analytics, and providing optimal user experiences across different platforms. ## What are the Most Popular User Agents? The most popular User Agents in 2024 are primarily from Chrome, Safari, Firefox, and Edge browsers across desktop and mobile platforms. Here are the key trends: - **Chrome on Windows** - The most common desktop combination, typically Windows 10/11 with Chrome 120+ - **Safari on iPhone** - Dominant mobile browser on iOS devices, usually the latest iOS versions - **Chrome on Android** - Leading Android browser across various device manufacturers - **Safari on macOS** - Popular among Mac users, especially developers and designers - **Edge on Windows** - Growing market share as Microsoft's default browser - **Firefox** - Maintains steady usage among privacy-conscious users Mobile User Agents now account for over 60% of web traffic globally, with Chrome and Safari dominating. Desktop usage remains strong for productivity and professional applications. The diversity of User Agents continues to grow with new devices like smart TVs, gaming consoles, and IoT devices accessing web content. ## How Can I Change My User Agent? Changing your User Agent can be useful for testing, development, or accessing content optimized for different browsers. Here are several methods: #### Browser Developer Tools Most modern browsers allow temporary User Agent changes: - **Chrome/Edge** : Open DevTools (F12) → Network Conditions → User Agent → Uncheck "Use browser default" - **Firefox** : Open DevTools (F12) → Responsive Design Mode → Settings → Custom User Agent - **Safari** : Enable Develop menu → User Agent → Select or enter custom #### Browser Extensions Popular extensions for permanent User Agent switching: - User-Agent Switcher and Manager - User-Agent Switcher for Chrome - Random User-Agent #### Command Line Browsers # Chrome with custom User Agent chrome --user-agent="Custom User Agent String" # cURL with custom User Agent curl -H "User-Agent: Custom User Agent" https://testingbot.com **Note:** Changing your User Agent may affect website functionality as some sites deliver different content based on the detected browser. Always test thoroughly when using custom User Agents in production environments. ## How to Get User Agent in Different Programming Languages ### JavaScript Browser & Node.js // Browser JavaScript const userAgent = navigator.userAgent; console.log('User Agent:', userAgent); // Node.js - Getting client User Agent in Express const express = require('express'); const app = express(); app.get('/', (req, res) => { const userAgent = req.headers['user-agent']; res.json({ userAgent }); }); // Setting custom User Agent in Node.js fetch fetch('https://api.testingbot.com', { headers: { 'User-Agent': 'MyApp/1.0.0' } }); ### Python Flask & Requests # Flask - Getting client User Agent from flask import Flask, request app = Flask( __name__ ) @app.route('/') def index(): user_agent = request.headers.get('User-Agent') return {'user_agent': user_agent} # Using requests library with custom User Agent import requests headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0' } response = requests.get('https://testingbot.com', headers=headers) # Getting User Agent from HTTP request from http.server import BaseHTTPRequestHandler class Handler(BaseHTTPRequestHandler): def do_GET(self): user_agent = self.headers.get('User-Agent') print(f"User Agent: {user_agent}") ### PHP Server & cURL [ 'header' => "User-Agent: MyApp/1.0\r\n" ] ]; $context = stream_context_create($options); $content = file_get_contents('https://testingbot.com', false, $context); ?> ### Ruby Rails & Net::HTTP # Rails - Getting client User Agent class ApplicationController < ActionController::Base def index user_agent = request.user_agent render json: { user_agent: user_agent } end end # Using Net::HTTP with custom User Agent require 'net/http' require 'uri' uri = URI('https://testingbot.com') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['User-Agent'] = 'MyRubyApp/1.0' response = http.request(request) # Using HTTParty gem require 'httparty' response = HTTParty.get('https://testingbot.com', headers: { 'User-Agent' => 'MyApp/1.0' } ) ### Java Servlet & HttpClient // Servlet - Getting client User Agent import javax.servlet.http.HttpServletRequest; public class UserAgentServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) { String userAgent = request.getHeader("User-Agent"); System.out.println("User Agent: " + userAgent); } } // Using HttpURLConnection URL url = new URL("https://testingbot.com"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestProperty("User-Agent", "MyJavaApp/1.0"); // Using Apache HttpClient CloseableHttpClient client = HttpClients.custom() .setUserAgent("MyApp/1.0") .build(); HttpGet request = new HttpGet("https://testingbot.com"); CloseableHttpResponse response = client.execute(request); // Spring Boot @RestController public class UserAgentController { @GetMapping("/") public String getUserAgent(@RequestHeader("User-Agent") String userAgent) { return userAgent; } } ### C# ASP.NET & HttpClient // ASP.NET Core - Getting client User Agent public class HomeController : Controller { public IActionResult Index() { string userAgent = Request.Headers["User-Agent"].ToString(); return Json(new { userAgent }); } } // Using HttpClient with custom User Agent using var client = new HttpClient(); client.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp/1.0"); var response = await client.GetAsync("https://testingbot.com"); // WebClient (legacy) using var webClient = new WebClient(); webClient.Headers.Add("User-Agent", "MyApp/1.0"); string result = webClient.DownloadString("https://testingbot.com"); // ASP.NET Core Middleware public class UserAgentMiddleware { public async Task InvokeAsync(HttpContext context) { var userAgent = context.Request.Headers["User-Agent"].ToString(); Console.WriteLine($"User Agent: {userAgent}"); await _next(context); } } ### Go net/http package main import ( "fmt" "net/http" ) // HTTP Server - Getting client User Agent func handler(w http.ResponseWriter, r *http.Request) { userAgent := r.Header.Get("User-Agent") fmt.Fprintf(w, "User Agent: %s", userAgent) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) } // HTTP Client - Setting custom User Agent client := &http.Client{} req, _ := http.NewRequest("GET", "https://testingbot.com", nil) req.Header.Set("User-Agent", "MyGoApp/1.0") resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close() ### Perl CGI & LWP #!/usr/bin/perl use strict; use warnings; # CGI - Getting client User Agent use CGI; my $q = CGI->new; my $user_agent = $q->user_agent(); print "User Agent: $user_agent\n"; # Using LWP::UserAgent use LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->agent("MyPerlBot/1.0"); my $response = $ua->get('https://testingbot.com'); if ($response->is_success) { print $response->decoded_content; } # Using HTTP::Tiny use HTTP::Tiny; my $http = HTTP::Tiny->new( agent => 'MyPerlApp/1.0' ); my $response = $http->get('https://testingbot.com'); ### Objective-C iOS & macOS // Getting system User Agent in iOS/macOS #import // Method 1: Using UIWebView (deprecated) UIWebView *webView = [[UIWebView alloc] init]; NSString *userAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; NSLog(@"User Agent: %@", userAgent); // Method 2: Using WKWebView #import WKWebView *webView = [[WKWebView alloc] init]; [webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(NSString *userAgent, NSError *error) { NSLog(@"User Agent: %@", userAgent); }]; // Setting custom User Agent with NSURLRequest NSURL *url = [NSURL URLWithString:@"https://testingbot.com"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setValue:@"MyIOSApp/1.0" forHTTPHeaderField:@"User-Agent"]; // Using NSURLSession NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // Handle response }]; [task resume]; ### Swift iOS & macOS import UIKit import WebKit // Getting User Agent with WKWebView let webView = WKWebView() webView.evaluateJavaScript("navigator.userAgent") { (result, error) in if let userAgent = result as? String { print("User Agent: \(userAgent)") } } // Setting custom User Agent with URLRequest var request = URLRequest(url: URL(string: "https://testingbot.com")!) request.setValue("MySwiftApp/1.0", forHTTPHeaderField: "User-Agent") // Using URLSession let task = URLSession.shared.dataTask(with: request) { data, response, error in // Handle response } task.resume() // SwiftUI with custom User Agent struct WebView: UIViewRepresentable { func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() webView.customUserAgent = "MyCustomApp/1.0" return webView } } ### Rust Actix-web & Reqwest // Actix-web - Getting client User Agent use actix_web::{web, App, HttpRequest, HttpServer, Result}; async fn index(req: HttpRequest) -> Result { let user_agent = req.headers() .get("user-agent") .and_then(|h| h.to_str().ok()) .unwrap_or("Unknown"); Ok(format!("User Agent: {}", user_agent)) } #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| App::new().route("/", web::get().to(index))) .bind("127.0.0.1:8080")? .run() .await } // Using Reqwest with custom User Agent use reqwest; #[tokio::main] async fn main() -> Result<(), Box> { let client = reqwest::Client::builder() .user_agent("MyRustApp/1.0") .build()?; let response = client .get("https://testingbot.com") .send() .await?; Ok(()) } ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/image-extractor [Tools](https://testingbot.com/free-online-tools)Data Generators # Image Extractor Extract images from any website Extract all images from any public website including background images, dynamically loaded images and SVG elements. Find and download images in various formats including JPEG, PNG, WebP, SVG and more from any webpage. Enter URL: ![Extracting Images](https://testingbot.com/assets/loading-0406eae1b17f4903931d9817122fdfbe585651d8fb63e564cf9def4c609fb9f7.gif) ### Error ### Extracted Images: This image extraction tool finds all images on a webpage, including background images, dynamically loaded images and embedded SVG elements. It provides detailed information about each image including dimensions, file type and download options. The tool is perfect for web designers, developers and content creators who need to analyze or collect images from websites for various purposes. ## What Is the Image Extractor Tool? The Image Extractor Tool is a powerful web-based utility that automatically discovers and extracts all images from any public website. Unlike simple image scrapers, this tool uses advanced browser automation to find images that are dynamically loaded, set as CSS background images, or embedded as SVG elements. The tool provides comprehensive image analysis including file format detection, dimension measurements and direct download capabilities for each discovered image. ## What Are the Use Cases for This Tool? This image extraction tool has numerous practical applications across different fields: - **Web Design & Development:** Analyze competitor websites, extract design assets or audit image usage across web properties - **Content Creation:** Gather reference images, mood boards or inspiration from various websites - **Digital Marketing:** Research visual trends, analyze competitor imagery or collect assets for campaigns - **Research & Analysis:** Academic research, market analysis or visual content studies - **Quality Assurance:** Test image loading, validate image formats or audit website assets This free tool supports all major image formats including `JPEG`, `PNG`, `WebP`, `SVG`, `GIF` and more, making it versatile for any image extraction needs. ## How to Use the Tool? Using the Image Extractor Tool is straightforward: 1. Enter the URL of the website you want to extract images from in the input field 2. Click the "Extract Images" button to start the extraction process 3. Wait for the tool to analyze the webpage and discover all images 4. Browse the results in the image grid, showing thumbnails with image details 5. Click the download button on any image to save it to your device The tool will display each image with its dimensions, file type and file size, making it easy to identify the images you need. ## What Are the Advantages of This Tool? Our Image Extractor Tool offers several key advantages over manual image collection or basic scrapers: - **Comprehensive Detection:** Finds all images including background images, lazy-loaded content and dynamically generated images - **Multiple Format Support:** Handles JPEG, PNG, WebP, SVG, GIF and other modern image formats - **Detailed Information:** Provides image dimensions, file size and format details for each discovered image - **Browser Automation:** Uses real browser rendering to ensure all images are discovered, even those loaded by JavaScript - **Direct Downloads:** One-click download functionality for any extracted image - **No Installation Required:** Works entirely in your web browser without any software installation - **Privacy Focused:** Images are processed securely without storing or caching your data The tool is perfect for professionals who need reliable, comprehensive image extraction with detailed metadata. ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/unix-timestamp-converter [Tools](https://testingbot.com/free-online-tools)Time & Date # Unix Timestamp Converter Convert epoch time instantly Convert Unix timestamps to human-readable dates and vice versa. Get the current Unix timestamp with real-time updates. ## Current Unix Timestamp 0 Seconds since Jan 01 1970 (UTC) Current time Copy Timestamp ## Convert Timestamp to Date Enter Unix timestamp Convert **GMT:** **Your Time Zone:** **Relative:** ## Convert Date to Timestamp Year MonthJanuaryFebruaryMarchAprilMayJuneJulyAugustSeptemberOctoberNovemberDecember Day Hour (24hr) Minutes Seconds Convert to Unix Timestamp **Unix Timestamp:** **GMT:** **Your Time Zone:** **Relative:** ## Current Epoch Information **Date:** **UTC:** **ISO 8601:** **RFC 822:** **RFC 2822:** **RFC 3339:** RFC Standards: [RFC 822](https://tools.ietf.org/html/rfc822), [RFC 1036](https://tools.ietf.org/html/rfc1036), [RFC 1123](https://tools.ietf.org/html/rfc1123), [RFC 2822](https://tools.ietf.org/html/rfc2822), [RFC 3339](https://tools.ietf.org/html/rfc3339) ## What is the Unix timestamp? The Unix timestamp (also known as Unix time, POSIX time, or epoch time) is a system for describing points in time: the number of seconds that have elapsed since January 1, 1970, at 00:00:00 UTC (Coordinated Universal Time). This date is known as the Unix epoch. Unix timestamps are widely used in programming and computing because they provide a simple, universal way to represent time that is independent of time zones and calendar systems. They are stored as integers, making them easy to work with in databases and programming languages. ## Why should I use a Unix timestamp? Unix timestamps offer several advantages for developers and system administrators: - **Universal Standard:** Works across all time zones and doesn't require time zone conversion - **Simplicity:** Stored as a single integer value, making calculations and comparisons easy - **Efficiency:** Takes up minimal storage space compared to formatted date strings - **Sorting:** Natural chronological ordering when sorted numerically - **Database-friendly:** Most databases have built-in functions to work with Unix timestamps - **API Integration:** Many APIs use Unix timestamps for date/time data exchange ## What happens on January 19, 2038? January 19, 2038, at 03:14:07 UTC marks the "Year 2038 problem" or "Y2038 bug." This is when 32-bit signed integer Unix timestamps will overflow, rolling over from 2,147,483,647 to -2,147,483,648, which would be interpreted as December 13, 1901. This issue affects systems that use 32-bit integers to store Unix timestamps. However, most modern systems have already migrated to 64-bit timestamps, which won't have this problem for approximately 292 billion years. The transition to 64-bit systems and updated software has largely mitigated this concern for contemporary applications. ## How to get Unix timestamp in programming languages ### Get current Unix timestamp: **JavaScript:** `Math.floor(Date.now() / 1000)` **PHP:** `time()` **Python:** `int(time.time())` **Ruby:** `Time.now.to_i` **Java:** `System.currentTimeMillis() / 1000` **C#:** `DateTimeOffset.UtcNow.ToUnixTimeSeconds()` **Go:** `time.Now().Unix()` **Bash:** `date +%s` **MySQL:** `SELECT UNIX_TIMESTAMP()` **PostgreSQL:** `SELECT EXTRACT(EPOCH FROM NOW())` ### Convert Unix timestamp to human-readable date: **JavaScript:** `new Date(timestamp * 1000).toString()` **PHP:** `date('Y-m-d H:i:s', $timestamp)` **Python:** `datetime.fromtimestamp(timestamp)` **Ruby:** `Time.at(timestamp)` **Java:** `new Date(timestamp * 1000)` **C#:** `DateTimeOffset.FromUnixTimeSeconds(timestamp)` **Go:** `time.Unix(timestamp, 0)` **Bash:** `date -d @timestamp` **MySQL:** `FROM_UNIXTIME(timestamp)` **PostgreSQL:** `TO_TIMESTAMP(timestamp)` ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/cron-expression-generator [Tools](https://testingbot.com/free-online-tools)Time & Date # Cron Expression Generator Build and test cron schedules This free tool allows you to enter a cron expression and get back a human-readable description along with the next 10 run times. You can also build a cron expression using the builder interface. ## Cron Expression Tester Enter Cron Expression Parse Format: minute hour day month weekday Quick Examples: Every minuteEvery hourDaily at midnightWeekly on MondayMonthly on 1stEvery 5 minutesEvery hour 9am-5pm weekdaysYearly on Jan 1st ## Expression Details Human Readable Daily at midnight Next 10 Run Times Field Breakdown 0 Minute At minute 0 0 Hour At hour 0 \* Day Every day \* Month Every month \* Weekday Every weekday ## Cron Expression Builder Minute (0-59)Every minute (\*)At minute 0Every 5 minutes (\*/5)Every 10 minutes (\*/10)Every 15 minutes (\*/15)Every 30 minutes (\*/30)At minute 0 and 30Custom... Hour (0-23)Every hour (\*)At midnight (0)Every 2 hours (\*/2)Every 4 hours (\*/4)Business hours (9-17)At midnight and noonCustom... Day of Month (1-31)Every day (\*)First day (1)Middle of month (15)Last day (L)Every 2 days (\*/2)Custom... Month (1-12)Every month (\*)January (1)Every quarter (\*/3)Every 6 months (\*/6)Custom... Day of Week (0-6, 0=Sunday)Every day (\*)Weekdays (1-5)Weekend (0,6)Monday (1)Friday (5)Custom... Generate Expression Generated Expression: `` Copy ## What is a Cron? Cron is a time-based job scheduler in Unix-like operating systems. It enables users to schedule jobs (commands or scripts) to run automatically at specified times, dates, or intervals. Cron expressions are strings that define when and how often a scheduled task should run. A cron expression consists of five fields separated by spaces: minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-6, where 0 is Sunday). Special characters like asterisk (\*) for "any value", comma (,) for multiple values, dash (-) for ranges and slash (/) for step values provide flexibility in scheduling. ## How can I use crons for scheduling? Cron expressions are widely used for scheduling automated tasks across various platforms and applications: - **System Administration:** Schedule backups, log rotation, system updates and maintenance tasks - **Web Applications:** Trigger periodic data processing, send scheduled emails or generate reports - **CI/CD Pipelines:** Run automated builds, tests, or deployments on a schedule - **Monitoring:** Execute health checks, collect metrics, or run diagnostic scripts at regular intervals - **Data Processing:** Schedule ETL jobs, data synchronization or batch processing tasks Common cron patterns include: "0 2 \* \* \*" for daily at 2 AM, "0 \*/4 \* \* \*" for every 4 hours, "0 9 \* \* 1-5" for weekdays at 9 AM, and "\*/15 \* \* \* \*" for every 15 minutes. ## TestingBot allows adding codeless tests with cron format to do scheduled testing TestingBot's [codeless testing platform](https://testingbot.com/features/ai-testing) integrates cron expressions for powerful scheduled test automation. You can set up your tests to run automatically at specified intervals without writing any code, ensuring continuous validation of your web applications and APIs. With TestingBot's cron-based scheduling, you can: - **Run regression tests nightly:** Use "0 2 \* \* \*" to execute your test suite at 2 AM daily when traffic is low - **Monitor critical paths hourly:** Set "0 \* \* \* \*" to verify essential user journeys every hour - **Weekend maintenance checks:** Schedule "0 10 \* \* 6,0" for Saturday and Sunday morning validations - **Get instant alerts:** Receive notifications via email, Slack, or webhooks when scheduled tests fail - **Track test history:** Review detailed reports and trends from all scheduled test runs This automated approach helps detect issues early, reduces manual testing effort, and ensures your application remains functional 24/7. Simply create your test scenario using TestingBot's codeless recorder, add a cron schedule, and let the platform handle the rest. ## Cron Expression Reference ### Field Values | Field | Allowed Values | Special Characters | | --- | --- | --- | | Minute | 0-59 | , - \* / | | Hour | 0-23 | , - \* / | | Day of Month | 1-31 | , - \* / L W | | Month | 1-12 or JAN-DEC | , - \* / | | Day of Week | 0-6 or SUN-SAT | , - \* / L # | ### Special Characters **\* (asterisk):** Matches any value. "\* \* \* \* \*" runs every minute **, (comma):** Separates multiple values. "0,30 \* \* \* \*" runs at minute 0 and 30 **- (dash):** Defines a range. "9-17 \* \* \* \*" runs from 9 AM to 5 PM **/ (slash):** Defines step values. "\*/15 \* \* \* \*" runs every 15 minutes **L:** Last day/weekday of month. "0 0 L \* \*" runs on the last day of the month **W:** Nearest weekday. "0 0 15W \* \*" runs on the weekday nearest to the 15th **#:** Nth occurrence. "0 0 \* \* 5#2" runs on the second Friday ### Common Examples `0 0 * * *` - Daily at midnight `0 */6 * * *` - Every 6 hours `0 0 * * 1` - Weekly on Monday `0 0 1 * *` - Monthly on the 1st `0 0 1 1 *` - Yearly on January 1st `*/30 9-17 * * 1-5` - Every 30 minutes during business hours on weekdays ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/whats-my-ip-address [Tools](https://testingbot.com/free-online-tools)Network Tools # What's My IP Address? Find your public IP instantly Find out your public IP address, location, ISP, and other network information instantly with our free IP lookup tool. ## Your IP Address Information Detecting your IP address... ### Your Public IP Address IPv4 IPv6 Copy IP Address ### Network Information Decimal:- Hostname:- ASN:- ISP:- Services:- ### Location Information Country:- State/Region:- City:- Postal Code:- Timezone:- Latitude:- Longitude:- ### Your Location on Map ### Browser Information User Agent: - Language:- Referrer:- ## What's my IP address? Your IP address is a unique identifier assigned to your device when it connects to the internet. This tool shows you both your IPv4 and IPv6 addresses, along with detailed information about your network connection and approximate location. The IP address displayed here is your **public IP address** - the one that websites and online services see when you connect to them. This is different from your private IP address used within your local network. ## What is a public IP address? A public IP address is a globally unique address that identifies your device on the internet. Unlike private IP addresses (used within your home or office network), public IP addresses are assigned by your Internet Service Provider (ISP) and are visible to websites and online services. Key characteristics of public IP addresses: - **Globally unique:** No two devices on the internet can have the same public IP address at the same time - **ISP assigned:** Your internet provider assigns and manages your public IP address - **Location identifiable:** Public IP addresses can be used to determine your approximate geographic location - **Dynamic or static:** Most home users have dynamic IPs that change periodically, while businesses often have static IPs ## How does my public IP address affect me? Your public IP address affects your online experience in several ways: - **Geographic restrictions:** Some websites and streaming services use your IP to determine your location and may restrict content based on your country - **Website analytics:** Websites use IP addresses to track visitor statistics, detect fraud, and provide location-specific content - **Online security:** Your IP can be used to identify suspicious activity or block malicious traffic - **Network troubleshooting:** IT administrators use IP addresses to diagnose and resolve network issues - **Privacy concerns:** Your IP address can potentially be used to track your online activities across different websites ## Should I change my IP address? Whether you should change your IP address depends on your specific needs and concerns: **Reasons you might want to change your IP:** - Access geo-restricted content from other regions - Enhance privacy and reduce online tracking - Bypass network restrictions or censorship - Resolve connectivity issues with certain websites - Protect against DDoS attacks or harassment **Methods to change your IP address:** - Restart your modem/router (may work for dynamic IPs) - Contact your ISP to request a new IP address - Use a VPN (Virtual Private Network) service - Use a proxy server - Use mobile data instead of your home internet ## How do I show my IP address? There are several ways to find and display your IP address: **Online tools (like this one):** - Visit websites that automatically detect and display your public IP - These tools often provide additional information like location and ISP details - Quick and easy method that works on any device with internet access **Command line methods:** - **Windows:** `ipconfig` (local IP) or `nslookup myip.opendns.com resolver1.opendns.com` (public IP) - **Mac/Linux:** `ifconfig` (local IP) or `curl ifconfig.me` (public IP) - **Universal:** `curl ipinfo.io` for detailed IP information ## What are proxies, how do they change my IP? A proxy server acts as an intermediary between your device and the internet. When you use a proxy, your internet traffic is routed through the proxy server, which then communicates with websites on your behalf. **How proxies change your IP address:** - Websites see the proxy server's IP address instead of your real IP - Your actual IP address is hidden from the websites you visit - The proxy server's location determines what websites think is your location **Types of proxies:** - **HTTP proxies:** Work with web browsers and HTTP traffic - **SOCKS proxies:** Handle various types of traffic, more versatile - **Transparent proxies:** Don't hide your IP, mainly used for caching - **Anonymous proxies:** Hide your IP but identify themselves as proxies - **Elite proxies:** Hide your IP and don't identify as proxies **Proxy vs VPN:** While both change your apparent IP address, VPNs encrypt your entire internet connection and typically offer better security and privacy than basic proxy servers. ## Technical References Internet Protocol Standards: [RFC 791 (IPv4)](https://tools.ietf.org/html/rfc791), [RFC 2460 (IPv6)](https://tools.ietf.org/html/rfc2460), [RFC 1918 (Private Networks)](https://tools.ietf.org/html/rfc1918), [RFC 6890 (Special-Use IP Addresses)](https://tools.ietf.org/html/rfc6890) ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [My GPS Location](https://testingbot.com/free-online-tools/my-gps-location) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/free-online-tools/my-gps-location [Tools](https://testingbot.com/free-online-tools)Network Tools # My GPS Location Get your coordinates from browser Find your current GPS coordinates from your browser. Get your latitude, longitude and address details instantly. ## What are my coordinates? Click the button below to detect your current GPS location Detect My Location Detecting your location... Try Again ### My location coordinates are: Latitude Longitude Copy Coordinates Refresh ### What is my location? Looking up address... My location address is: City:- State:- Country:- Postal Code:- Timezone:- What3Words:- Could not retrieve address information ### GPS Details Accuracy:- Altitude:- Heading:- Speed:- Geohash:- Timestamp:- ### Where am I? My Location Map ## What is GPS location? GPS (Global Positioning System) location refers to the coordinates that pinpoint your exact position on Earth. It uses a constellation of satellites orbiting Earth to determine your location with high precision. Your GPS location consists of two main components: - **Latitude:** Your north-south position, measured in degrees from -90 (South Pole) to +90 (North Pole), with 0 at the equator - **Longitude:** Your east-west position, measured in degrees from -180 to +180, with 0 at the Prime Meridian (Greenwich, London) Modern smartphones and browsers can access GPS data to provide location-based services, navigation, weather information and more. ## GPS coordinates: how do they work? How accurate are they? GPS works by receiving signals from multiple satellites (at least 4) and calculating your position based on the time it takes for each signal to reach your device. This process is called **trilateration**. **Accuracy levels:** - **Standard GPS:** 3-5 meters accuracy under open sky conditions - **Assisted GPS (A-GPS):** Uses cell towers and Wi-Fi to improve accuracy and speed of location fix - **DGPS (Differential GPS):** Can achieve sub-meter accuracy using ground-based reference stations - **RTK GPS:** Real-Time Kinematic GPS can achieve centimeter-level accuracy **Factors affecting accuracy:** - Number of visible satellites - Atmospheric conditions (ionosphere interference) - Urban canyons (tall buildings blocking signals) - Indoor vs outdoor positioning - Device hardware quality ## How can I get GPS coordinates in Java, C#, Ruby, Python and NodeJS? Here's how to get GPS coordinates programmatically in different languages: **JavaScript (Browser):** navigator.geolocation.getCurrentPosition( (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; console.log(`Latitude: ${lat}, Longitude: ${lng}`); }, (error) => console.error(error) ); **Python:** import geocoder g = geocoder.ip('me') print(f"Latitude: {g.lat}, Longitude: {g.lng}") **Java (Android):** LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE); Location location = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); double lat = location.getLatitude(); double lng = location.getLongitude(); **C# (.NET):** var locator = new Geolocator(); var position = await locator.GetGeopositionAsync(); var lat = position.Coordinate.Point.Position.Latitude; var lng = position.Coordinate.Point.Position.Longitude; **Ruby:** require 'geocoder' result = Geocoder.search("your-ip-address").first puts "Latitude: #{result.latitude}, Longitude: #{result.longitude}" **Node.js:** const geoip = require('geoip-lite'); const ip = "your-ip-address"; const geo = geoip.lookup(ip); console.log(`Latitude: ${geo.ll[0]}, Longitude: ${geo.ll[1]}`); ## How to mock GPS location details with Selenium and Appium? **TestingBot** allows you to mock GPS location on both simulators/emulators and physical mobile devices during automated testing. This is essential for testing location-based features in your mobile applications. **Mocking GPS with Selenium (Chrome DevTools Protocol):** # Python example with Selenium from selenium import webdriver driver = webdriver.Chrome() driver.execute_cdp_cmd("Emulation.setGeolocationOverride", { "latitude": 51.175570, "longitude": 3.945113, "accuracy": 100 }) **Mocking GPS with Appium (iOS/Android):** # Python example with Appium driver.set_location(51.175570, 3.945113, 10) # lat, lng, altitude With TestingBot's real device cloud, you can: - Test location-based app features with custom coordinates - Simulate movement between locations for navigation testing - Test geofencing functionality - Verify location permissions handling [Learn more about TestingBot's real device testing](https://testingbot.com/mobile/realdevicetesting) ## Popular GPS coordinates of famous places Here are GPS coordinates for some famous landmarks around the world: | Location | Latitude | Longitude | | --- | --- | --- | | Eiffel Tower, Paris | 48.8584 | 2.2945 | | Statue of Liberty, New York | 40.6892 | -74.0445 | | Big Ben, London | 51.5007 | -0.1246 | | Sydney Opera House | -33.8568 | 151.2153 | | Christ the Redeemer, Rio | -22.9519 | -43.2105 | | Machu Picchu, Peru | -13.1631 | -72.5450 | | Great Wall of China | 40.4319 | 116.5704 | | Taj Mahal, India | 27.1751 | 78.0421 | | Colosseum, Rome | 41.8902 | 12.4922 | | Burj Khalifa, Dubai | 25.1972 | 55.2744 | ### All Tools #### Accessibility - [Color Contrast Checker](https://testingbot.com/free-online-tools/color-contrast-checker) #### Converter - [Unix Timestamp Converter](https://testingbot.com/free-online-tools/unix-timestamp-converter) #### Formatter - [Puppeteer to Playwright Converter](https://testingbot.com/free-online-tools/puppeteer-to-playwright-converter) - [JSON Prettifier](https://testingbot.com/free-online-tools/json-prettify) - [HTML Escaper](https://testingbot.com/free-online-tools/html-escape) - [XML Prettifier](https://testingbot.com/free-online-tools/xml-prettify) - [Remove Whitespace](https://testingbot.com/free-online-tools/remove-all-whitespace) - [Text to One Line](https://testingbot.com/free-online-tools/text-to-one-line) - [PX to REM Converter](https://testingbot.com/free-online-tools/px-to-rem-converter) #### Generator - [Random Avatar Generator](https://testingbot.com/free-online-tools/free-avatar-generator) - [Placeholder Image Generator](https://testingbot.com/free-online-tools/placeholder-image-generator) - [Random Address Generator](https://testingbot.com/free-online-tools/random-address-generator) - [Credit Card Generator](https://testingbot.com/free-online-tools/credit-card-number-generator) - [Random Number Generator](https://testingbot.com/free-online-tools/random-number-generator) - [JWT Parser](https://testingbot.com/free-online-tools/jwt-parser) - [Fake Person Generator](https://testingbot.com/free-online-tools/fake-person-generator) - [Hash Text](https://testingbot.com/free-online-tools/hash-text) - [Lorem Ipsum Generator](https://testingbot.com/free-online-tools/lorem-ipsum-generator) - [Random IP Generator](https://testingbot.com/free-online-tools/random-ip-generator) - [Random GUID Generator](https://testingbot.com/free-online-tools/random-guid-generator) - [Character Count](https://testingbot.com/free-online-tools/character-count) - [ASCII to Binary](https://testingbot.com/free-online-tools/ascii-to-binary) - [Random Color Generator](https://testingbot.com/free-online-tools/random-color-generator) - [Open Graph Meta Generator](https://testingbot.com/free-online-tools/og-meta-generator) - [QR Code Generator](https://testingbot.com/free-online-tools/qr-code-generator) - [Device Information](https://testingbot.com/free-online-tools/device-information) - [User Agent Parser](https://testingbot.com/free-online-tools/user-agent-parser) - [Image Extractor](https://testingbot.com/free-online-tools/image-extractor) #### Network - [CORS Tester](https://testingbot.com/free-online-tools/cors-tester) - [What's My IP Address](https://testingbot.com/free-online-tools/whats-my-ip-address) #### Scheduler - [Cron Expression Generator](https://testingbot.com/free-online-tools/cron-expression-generator) #### Speed - [Critical CSS Generator](https://testingbot.com/free-online-tools/critical-css-generator) [View all tools](https://testingbot.com/free-online-tools) --- URL: https://testingbot.com/mobile-testing ## Test On Different Mobile Devices Online - **Wide range of Mobile devices** Test your mobile apps and websites on physical mobile devices. TestingBot offers both high end devices, as well as low end devices. - **Mobile Device Farm** No need to purchase and maintain your own device farm. Get instant access to a remote device farm, ready for your testing needs. - **Secure and private** TestingBot provides pristine devices, without any jailbreak or tweaks. - **Real-time debugging** Debug your websites & mobile apps. Access crash reports and logs to instantly fix bugs. - **Tap, Swipe, Pinch & more** Tap, swipe, pinch and perform other gestures. Audio from the device is streamed during manual testing. - **Test various network speeds** Run mobile tests with different network speeds: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ### Trusted by some of the world's most innovative companies - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ![TestingBot Logo](https://testingbot.com/assets/logo-head-c3ea57ac5c8158d3f911af8093ee89e02c51e3e27f82c678cf90fc9e0d66cc6c.svg) ## Sign up for a Free Trial Start testing your apps with TestingBot. No credit card required! [Start Free Trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-17-pro # Test on Apple iPhone 17 Pro Automated, manual and visual testing on Apple iPhone 17 Pro. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 17 Pro. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 17 Pro device](https://testingbot.com/assets/features/devices/apple-iphone-17-pro-e5c4933d59ea9c31b7e83f74643dc802279b8a707341712b14e12f42dc9c6701.png) Trusted by some of the world's most innovative companies ## Testing on Apple iPhone 17 Pro ### Physical Apple iPhone 17 Pro Device Run automated Appium and XCUITests on a physical Apple iPhone 17 Pro device, located in the TestingBot device farm. ### Performance Testing Real-time insights into the performance of your app, running on iPhone 17 Pro. Accelerate your mobile testing on Apple iPhone 17 Pro. ### Secure Every test runs on a clean iPhone 17 Pro device, with no leftover data from previous sessions. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone 17 Pro: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone 17 Pro Device Information - Display:6.3" Super Retina XDR ProMotion OLED - Camera:48MP Pro camera system - Memory:8GB RAM - Li-Ion Battery:3950mAh - iOS Supported Versions:iOS 19 and higher - Processor:Apple A19 Pro chip - Weight:187g, 8.25mm thickness - Resolution:2796 x 1290 pixels, 19.5:9 ratio (~460 ppi) - Dimensions:146.6 x 70.6 x 8.25 mm - Material:Titanium design with Ceramic Shield front [Test on iPhone 17 Pro](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### Can I test on a private, dedicated iPhone 17 Pro? TestingBot offers [private devices](https://testingbot.com/enterprise/private-device-cloud), including iPhone 17 Pro. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone 17 Pro in the TestingBot remote device grid. ### Is Apple Intelligence testing supported? The iPhone 17 Pro devices we are hosting contain iOS 19 or higher, capable of using Apple Intelligence with enhanced Pro features. Apple Intelligence is a personal AI system that puts powerful generative models right at the core of your iPhone, with the Pro model offering additional AI capabilities and on-device processing power. ### How can I run automated tests with iOS 19 on iPhone 17 Pro? TestingBot offers full Appium 2 support for running iOS 19+ tests on iPhone 17 Pro. Connect to a physical Apple iPhone 17 Pro with its titanium design and ProMotion display, connected in a datacenter, available for automated, visual and manual testing. ### What Pro features can I test on iPhone 17 Pro? The iPhone 17 Pro features a ProMotion display with adaptive refresh rates up to 120Hz, ideal for testing smooth animations and scrolling in your apps. You can also test your app's camera integration with the advanced 48MP Pro camera system and take advantage of the A19 Pro chip's enhanced performance. ## Other iOS devices available for testing on TestingBot - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-17 # Test on Apple iPhone 17 Automated, manual and visual testing on Apple iPhone 17. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 17. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 17 device](https://testingbot.com/assets/features/devices/apple-iphone-17-c4fc9297d24f94ca74915a89abdf48a15fa137be92a3aabfe45ac12ff5e64d20.png) Trusted by some of the world's most innovative companies ## Testing on Apple iPhone 17 ### Physical Apple iPhone 17 Device Run automated Appium and XCUITests on a physical Apple iPhone 17 device, located in the TestingBot device farm. ### Performance Testing Real-time insights into the performance of your app, running on iPhone 17. Accelerate your mobile testing on Apple iPhone 17. ### Secure Every test runs on a clean iPhone 17 device, with no leftover data from previous sessions. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone 17: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone 17 Device Information - Display:6.3" Super Retina XDR OLED - Camera:48MP Fusion camera - Memory:8GB RAM - Li-Ion Battery:3800mAh - iOS Supported Versions:iOS 19 and higher - Processor:Apple A19 chip - Weight:170g, 7.8mm thickness - Resolution:2556 x 1179 pixels, 19.5:9 ratio (~460 ppi) - Dimensions:147.6 x 71.6 x 7.8 mm [Test on iPhone 17](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### Can I test on a private, dedicated iPhone 17? TestingBot offers [private devices](https://testingbot.com/enterprise/private-device-cloud), including iPhone 17. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone 17 in the TestingBot remote device grid. ### Is Apple Intelligence testing supported? The iPhone 17 devices we are hosting contain iOS 19 or higher, capable of using Apple Intelligence. Apple Intelligence is a personal AI system that puts powerful generative models right at the core of your iPhone, enabling advanced on-device AI features. ### How can I run automated tests with iOS 19 on iPhone 17? TestingBot offers full Appium 2 support for running iOS 19+ tests on iPhone 17 and higher. Connect to a physical Apple iPhone 17, which is connected in a datacenter, available for automated, visual and manual testing. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-air # Test on Apple iPhone Air Automated, manual and visual testing on Apple iPhone Air. Check if your website and mobile app works and looks correctly on a remote Apple iPhone Air. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone Air device](https://testingbot.com/assets/features/devices/apple-iphone-air-e051c245f34eeaaee03969430b4b1b352445bbb6ff85789633de849e07debe49.png) Trusted by some of the world's most innovative companies ## Testing on Apple iPhone Air ### Physical Apple iPhone Air Device Run automated Appium and XCUITests on a physical Apple iPhone Air device, located in the TestingBot device farm. ### Performance Testing Real-time insights into the performance of your app, running on iPhone Air. Accelerate your mobile testing on Apple iPhone Air. ### Secure Every test runs on a clean iPhone Air device, with no leftover data from previous sessions. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone Air: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone Air Device Information - Display:6.6" Super Retina XDR OLED - Camera:48MP Fusion camera - Memory:8GB RAM - Li-Ion Battery:3000mAh - iOS Supported Versions:iOS 19 and higher - Processor:Apple A19 chip - Weight:145g, 5.5mm thickness - Resolution:2740 x 1260 pixels, 19.5:9 ratio (~456 ppi) - Dimensions:159.2 x 76.2 x 5.5 mm - Design:Ultra-thin aluminum design [Test on iPhone Air](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### Can I test on a private, dedicated iPhone Air? TestingBot offers [private devices](https://testingbot.com/enterprise/private-device-cloud), including iPhone Air. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone Air in the TestingBot remote device grid. ### Is Apple Intelligence testing supported? The iPhone Air devices we are hosting contain iOS 19 or higher, capable of using Apple Intelligence. Apple Intelligence is a personal AI system that puts powerful generative models right at the core of your iPhone, enabling advanced on-device AI features in an ultra-thin form factor. ### How can I run automated tests with iOS 19 on iPhone Air? TestingBot offers full Appium 2 support for running iOS 19+ tests on iPhone Air. Connect to a physical Apple iPhone Air, which is connected in a datacenter, available for automated, visual and manual testing. ### What makes the iPhone Air unique for testing? The iPhone Air features Apple's thinnest iPhone design at just 5.5mm, with a larger 6.6" display in an ultra-lightweight 145g body. Test your apps on this unique form factor to ensure optimal performance and UI rendering on the larger display while maintaining responsiveness on the energy-efficient design. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-16 # Test on Apple iPhone 16 Automated, manual and visual testing on Apple iPhone 16. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 16. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 16 device](https://testingbot.com/assets/features/devices/apple-iphone-16-5acf3e500375759c2c5a3ba81ad49bcf14477c8bdb6f87c53ccfe27a3b68410c.png) Trusted by some of the world's most innovative companies ## Testing on Apple iPhone 16 ### Physical Apple iPhone 16 Device Run automated Appium and XCUITests on a physical Apple iPhone 16 device, located in the TestingBot device farm. ### Performance Testing Real-time insights into the performance of your app, running on iPhone 16. Accelerate your mobile testing on Apple iPhone 16. ### Secure Every test runs on a clean iPhone 16 device, with no leftover data from previous sessions. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone 16: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone 16 Device Information - Display:6.2" - Camera:48MP - Memory:8GB RAM - Li-Ion Battery:3589mAh - iOS Supported Versions:iOS 17 and higher - Processor:Apple A17 Bionic - Weight:174g, 7.6mm thickness - Resolution:2778 x 1284 pixels, 19.5:9 ratio (~460 ppi) - Dimensions:147.8 x 72.1 x 7.6 mm [Test on iPhone 16](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### Can I test on a private, dedicated iPhone 16? TestingBot offers [private devices](https://testingbot.com/enterprise/private-device-cloud), including iPhone 16. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone 16 in the TestingBot remote device grid. ### Is Apple Intelligence testing supported? The iPhone 16 devices we are hosting contain iOS 18 or higher, capable of using Apple Intelligence. Apple Intelligence is a personal AI system that puts powerful generative models, such as ChatGPT, right at the core of your iPhone. ### How can I run automated tests with iOS 18 on iPhone 16? TestingBot offers full Appium 2 support for running iOS 18+ tests on iPhone 16 and higher. Connect to a physical Apple iPhone 16, which is connected in a datacenter, available for automated, visual and manual testing. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-15 # Test on Apple iPhone 15 Automated, manual and visual testing on Apple iPhone 15. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 15. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 15 device](https://testingbot.com/assets/features/devices/apple-iphone-15-662a081f53fc221670b9942dccbdd12a4f5bd07410e87c70af5569fe94d46081.png) Trusted by some of the world's most innovative companies ## Testing on Apple iPhone 15 ### Physical Apple iPhone 15 Device Run automated Appium and XCUITests on a physical Apple iPhone 15 device, located in the TestingBot devicefarm. ### Performance Testing Performance testing of your iOS app on iPhone 15. Check the speed of your app on an Apple iPhone 15 simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Realtime insights in the performance of your app, running on iPhone 15. Accelerate your mobile testing on Apple iPhone 15. ### Tap, Swipe, Pinch & more Tap, swipe, pinch and perform other gestures. Audio from the iPhone 15 device is streamed during interactive testing. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 15: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 15 Device Information - Display:6.1" - Camera:48MP + 12MP - Memory:6GB RAM - Li-Ion Battery:3349mAh - iOS Supported Versions:iOS 15 and higher - Processor:Apple A16 Bionic - Weight:171g, 7.80mm thickness - Resolution:1179 x 2556 pixels, 19.5:9 ratio (~461 ppi density) - Dimensions:147.6 x 71.6 x 7.80 mm (5.81 x 2.82 x 0.31 in) [Test on iPhone 15](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### Can I test on a private, dedicated iPhone 15? TestingBot offers [private devices](https://testingbot.com/enterprise/private-device-cloud), including iPhone 15. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone 15 in the TestingBot remote device grid. ### How can I run automated tests with iOS 17 on iPhone 15? You can use Appium 2 to run automated tests on iPhone 15, running iOS 17 and higher. Dedicated devices are always available to you and your team, ready to run your automated and manual tests on iPhone 15 in the TestingBot remote device grid. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-14 # Test on Apple iPhone 14 Automated, manual and visual testing on Apple iPhone 14. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 14. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 14 device](https://testingbot.com/assets/features/devices/apple-iphone-14-a1805155cadc3e04948c94d156e1a4b162510e35637b76a92f70dd0068c7365b.png) Trusted by some of the world's most innovative companies ## Automated and Manual testing on Apple iPhone 14 ### Physical Apple iPhone 14 Device Run Appium and XCUITests on a physical Apple iPhone 14 device, located in the TestingBot device lab. ### Performance Testing Realtime insights in the performance of your app, running on iPhone 14. Accelerate your mobile beta testing on Apple iPhone 14. ### Secure Every test runs on a cleanly wiped iPhone 14, without any jailbreaks or tweaks. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 14. ### Tap, Swipe, Pinch & more Interact with a iPhone 14, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 14: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 14 Device Information - Display:6.1" - Camera:12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:3279mAh - iOS Supported Versions:iOS 15 and higher - Processor:Apple A15 Bionic - Weight:172g, 7.8mm thickness - Resolution:1170 x 2532 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:146.7 x 71.5 x 7.8 mm (5.78 x 2.81 x 0.31 in) [Test on iPhone 14](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I run an automated test on iPhone 14? TestingBot offers [XCUITesting](https://testingbot.com/features/automation/xcuitest) on iPhone 14. To get started, please visit the [XCUITest documentation](https://testingbot.com/support/app-automate/xcuitest) for examples and options. ### It is 2026, should I test on Apple iPhone 14? Even though [iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) has been released at the end of September 2024, it's still a good idea to test on iPhone 14. While the adoption rate for new devices is higher for Apple devices than any other smartphone out there, it's important to test on older version of iPhone and iPad to guarantee backwards compatibility of older devices and older iOS versions. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-14-pro-max # Test on Apple iPhone 14 Pro Max Automated, manual and visual testing on Apple iPhone 14 Pro Max. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 14 Pro Max. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 14 Pro Max device](https://testingbot.com/assets/features/devices/apple-iphone-14-pro-max-303f994abc2ae35074cccbe58296deb2cbab76506ab16a5bf309636f9473ab4a.png) Trusted by some of the world's most innovative companies ## Automated and Live Testing on an Apple iPhone 14 Pro Max ### Apple iPhone 14 Pro Max iOS Simulator Run manual or automated tests, using Appium or XCUITest, on a remote Apple iPhone 14 Pro Max simulator. ### Performance Testing Performance testing of your iOS app on iPhone 14 Pro Max. Check the speed of your app on an Apple iPhone 14 Pro Max simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 14 Pro Max. ### Tap, Swipe, Pinch & more Take control of a iPhone 14 Pro Max, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 14 Pro Max: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 14 Pro Max Device Information - Display:6.7" - Camera:48MP + 12MP + 12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:4323mAh - iOS Supported Versions:iOS 16 and up - Processor:Apple A16 Bionic - Weight:240g, 7.85mm thickness - Resolution:1290 x 2796 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:160.7 x 77.6 x 7.85 mm (6.33 x 3.06 x 0.31 in) [Test on iPhone 14 Pro Max](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test with online on an iPhone 14 Pro Max? At TestingBot we provide access to Apple iPhone 14 Pro Max. Simply enter an URL or mobile app (ipa) file to test on an iPhone 14 Pro Max. Both the screen and the generated audio will be streamed to your browser, no plugins required. ### How can I debug on Apple iPhone 14 Pro Max? TestingBot embeds the Safari Developer Tools in the manual testing section. You can easily inspect your website for errors, inspect the DOM and trace network requests. During iOS app testing, you will get a live view of the generated iOS syslog and you can inspect your mobile app to find locators, similar to how the Accessibility Inspector on XCode works. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-14-pro # Test on Apple iPhone 14 Pro Automated, manual and visual testing on Apple iPhone 14 Pro. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 14 Pro. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 14 Pro device](https://testingbot.com/assets/features/devices/apple-iphone-14-pro-d8cb1eba82327581baab86c2c01f72ecbb132ff658d344e448acc995f847f354.png) Trusted by some of the world's most innovative companies ## Automated and Live Testing on an Apple iPhone 14 Pro ### Apple iPhone 14 Pro iOS Simulator Run manual or automated tests, using Appium or XCUITest, on a remote Apple iPhone 14 Pro simulator. ### Performance Testing Performance testing of your iOS app on iPhone 14 Pro. Check the speed of your app on an Apple iPhone 14 Pro simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 14 Pro. ### Tap, Swipe, Pinch & more Interact with a iPhone 14 Pro, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 14 Pro: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 14 Pro Device Information - Display:6.1" - Camera:48MP + 12MP + 12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:3200mAh - iOS Supported Versions:iOS 16 and up - Processor:Apple A16 Bionic - Weight:206g, 7.85mm thickness - Resolution:1179 x 2556 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:147.5 x 71.5 x 7.85 mm (5.81 x 2.81 x 0.31 in) [Test on iPhone 14 Pro](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 14 Pro? TestingBot provides remote Apple iPhone 14 Pro simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 14 Pro. ### Do I still need to test on an Apple iPhone 14 Pro? Apple iPhone 14 Pro is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-14-plus # Test on Apple iPhone 14 Plus Automated, manual and visual testing on Apple iPhone 14 Plus. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 14 Plus. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 14 Plus device](https://testingbot.com/assets/features/devices/apple-iphone-14-plus-348b35f65cc186619dca2f0a8343af6cdd626b77435e616eb38620ec420d8607.png) Trusted by some of the world's most innovative companies ## Remote Testing on an Apple iPhone 14 Plus ### Apple iPhone 14 Plus iOS Simulator Manual or automated testing, using Appium, XCUITest or Maestro, on a remote Apple iPhone 14 Plus simulator. ### Performance Testing Test the performance of your iOS app on iPhone 14 Plus. Verify the speed of your app on an Apple iPhone 14 Plus. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 14 Plus. ### Tap, Swipe, Pinch & more Interact with a iPhone 14 Plus, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 14 Plus: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 14 Plus Device Information - Display:6.7" - Camera:12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:4323mAh - iOS Supported Versions:iOS 16 and up - Processor:Apple A15 Bionic - Weight:203g, 7.80mm thickness - Resolution:1290 x 2796 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:160.7 x 77.6 x 7.80 mm (6.33 x 3.06 x 0.31 in) [Test on iPhone 14 Plus](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 14 Plus? TestingBot provides remote Apple iPhone 14 Plus simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on an iPhone 14 Plus. ### Do I still need to test on an Apple iPhone 14 Plus? Apple iPhone 14 Plus is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-se-2022 # Test on Apple iPhone SE 2022 Automated, manual and visual testing on Apple iPhone SE 2022. Check if your website and mobile app works and looks correctly on a remote Apple iPhone SE 2022. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone SE 2022 device](https://testingbot.com/assets/features/devices/apple-iphone-se-2022-3decc385349ec3621c248ab67b769129f9d5239219e9d81446f6e615144e13ec.png) Trusted by some of the world's most innovative companies ## Remote Testing on an Apple iPhone SE 2022 ### Apple iPhone SE 2022 Manual or automated testing, using Appium, XCUITest or Maestro, on a remote Apple iPhone SE 2022 simulator. ### Performance Testing Test the performance of your iOS app on iPhone SE 2022. Verify the speed of your app on an Apple iPhone SE 2022. ### Secure Every test runs on a clean iPhone SE 2022 device, with no leftover data from previous sessions. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone SE 2022: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone SE 2022 Device Information - Display:4.7" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:2018mAh - iOS Supported Versions:iOS 15.4 and higher - Processor:Apple A15 Bionic - Weight:144g, 7.3mm thickness - Resolution:750 x 1334 pixels, 16:9 ratio (~326 ppi density) - Dimensions:138.4 x 67.3 x 7.3 mm (5.45 x 2.65 x 0.29 in) [Test on iPhone SE 2022](https://testingbot.com/users/sign_up) ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-13-pro-max # Test on Apple iPhone 13 Pro Max Automated, manual and visual testing on Apple iPhone 13 Pro Max. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 13 Pro Max. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 13 Pro Max device](https://testingbot.com/assets/features/devices/apple-iphone-13-pro-max-10b11723e29eea8053f360e6d7291386dac47ffc797247a222008c1a99a6c67a.png) Trusted by some of the world's most innovative companies ## Online Testing on an Apple iPhone 13 Pro Max ### Apple iPhone 13 Pro Max iOS Device Ready to run your Appium and XCUITests on a remote Apple iPhone 13 Pro Max simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 13 Pro Max. Check the speed of your app on an Apple iPhone 13 Pro Max simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 13 Pro Max. ### Tap, Swipe, Pinch & more Interact with a iPhone 13 Pro Max, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 13 Pro Max: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 13 Pro Max Device Information - Display:6.7" - Camera:12MP + 12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:4352mAh - iOS Supported Versions:iOS 15 and higher - Processor:Apple A15 Bionic - Weight:238g, 7.65mm thickness - Resolution:1284 x 2778 pixels, 19.5:9 ratio (~458 ppi density) - Dimensions:160.8 x 78.1 x 7.65 mm (6.33 x 3.07 x 0.30 in) [Test on iPhone 13 Pro Max](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 13 Pro Max? TestingBot provides remote Apple iPhone 13 Pro Max simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 13 Pro Max. ### Do I still need to test on an Apple iPhone 13 Pro Max? Apple iPhone 13 Pro Max is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-13-pro # Test on Apple iPhone 13 Pro Automated, manual and visual testing on Apple iPhone 13 Pro. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 13 Pro. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 13 Pro device](https://testingbot.com/assets/features/devices/apple-iphone-13-pro-0c7447faff8ec8c8a6b5a6342969c21fcdf2c1794a3c08b803ec6127056af749.png) Trusted by some of the world's most innovative companies ## Automated and Manual testing on Apple iPhone 13 Pro ### Physical Apple iPhone 13 Pro Device Run Appium and XCUITests on a physical Apple iPhone 13 Pro device, located in the TestingBot remote device farm. ### Performance Testing Test the performance of your iOS app on iPhone 13 Pro. Test the battery level, perform a speed test, or use the camera for testing image and video related actions. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 13 Pro. ### Tap, Swipe, Pinch & more Interact with a iPhone 13 Pro, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 13 Pro: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 13 Pro Device Information - Display:6.1" - Camera:12MP + 12MP + 12MP - Memory:6GB RAM - Li-Ion Battery:3095mAh - iOS Supported Versions:iOS 15 up to iOS 16 - Processor:Apple A15 Bionic - Weight:204g, 7.65mm thickness - Resolution:1170 x 2532 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:146.7 x 71.5 x 7.65 mm (5.78 x 2.81 x 0.30 in) [Test on iPhone 13 Pro](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test my app online on an iPhone 13 Pro? You can test your iOS app on a remote Apple iPhone 13 Pro, located in a device farm in the TestingBot data center. Both [manual app testing](https://testingbot.com/support/app-live) as well as [automated Appium testing](https://testingbot.com/support/app-automate/appium) is available. You can choose to use Appium or XCUITest to run automated tests on this device. ### Do you offer iPhone 13 Pro simulators? At TestingBot, we offer both simulators and physical mobile devices to run tests on. iOS Simulators can be used to do quick smoke tests, whereas physical devices can be used to do more thorough testing of apps and websites. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-13 # Test on Apple iPhone 13 Automated, manual and visual testing on Apple iPhone 13. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 13. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 13 device](https://testingbot.com/assets/features/devices/apple-iphone-13-ffa26d1b3503794c02ba3283676de37894116b85aa358708c3231688b6c06fb6.png) Trusted by some of the world's most innovative companies ## Automated and Manual testing on Apple iPhone 13 ### Physical Apple iPhone 13 Device Run Appium and XCUITests on a physical Apple iPhone 13 device, located in the TestingBot device lab. ### Performance Testing Realtime insights in the performance of your app, running on iPhone 13. Accelerate your mobile beta testing on Apple iPhone 13. ### Secure Every test runs on a cleanly wiped iPhone 13, without any jailbreaks or tweaks. ### Insights Receive crash reports from iOS, debug possible Swift or Objective-C errors and more on a remote device. ### Tap, Swipe, Pinch & more Tap, swipe, pinch and perform other gestures. Audio from the iPhone 13 device is streamed during interactive testing. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 13: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 13 Device Information - Display:6.1" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:3240mAh - iOS Supported Versions:iOS 15 and higher - Processor:Apple A15 Bionic - Weight:174g, 7.65mm thickness - Resolution:1170 x 2532 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:146.7 x 71.5 x 7.65 mm (5.78 x 2.81 x 0.30 in) [Test on iPhone 13](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I run an XCUITest on iPhone 13? TestingBot provides the possiblity to run [XCUITests](https://testingbot.com/features/automation/xcuitest) on remote iPhones and iPads. To learn more about this, please visit the [XCUITest documentation](https://testingbot.com/support/app-automate/xcuitest). ### Is it important to test on Apple iPhone 13? iPhone 13 is still being used by a large number of mobile phone users, so it might be beneficial to test your website and mobile apps on this type of device. As many users have upgraded to a newer device, you might also be interested in testing on its successor: [iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14). ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-13-mini # Test on Apple iPhone 13 Mini Automated, manual and visual testing on Apple iPhone 13 Mini. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 13 Mini. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 13 Mini device](https://testingbot.com/assets/features/devices/apple-iphone-13-mini-d41c855fd5875832e077cab57d44bf8104a214f37b856e5674ac9bd5768ef2eb.png) Trusted by some of the world's most innovative companies ## Online Testing on an Apple iPhone 13 Mini ### Apple iPhone 13 Mini iOS Device Ready to run your Appium and XCUITests on a remote Apple iPhone 13 Mini simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 13 Mini. Check the speed of your app on an Apple iPhone 13 Mini simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 13 Mini. ### Tap, Swipe, Pinch & more Interact with a iPhone 13 Mini, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 13 Mini: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 13 Mini Device Information - Display:5.4" - Camera:12MP + 12MP - Memory:4GB RAM - Li-Ion Battery:2406mAh - iOS Supported Versions:iOS 15 up to iOS 16 - Processor:Apple A15 Bionic - Weight:140g, 7.65mm thickness - Resolution:1080 x 2340 pixels, 19.5:9 ratio (~476 ppi density) - Dimensions:131.5 x 64.2 x 7.65 mm (5.18 x 2.53 x 0.30 in) [Test on iPhone 13 Mini](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 13 Mini? TestingBot provides remote Apple iPhone 13 Mini simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 13 Mini. ### Do I still need to test on an Apple iPhone 13 Mini? Apple iPhone 13 Mini is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-se-2020 # Test on Apple iPhone SE 2020 Automated, manual and visual testing on Apple iPhone SE 2020. Check if your website and mobile app works and looks correctly on a remote Apple iPhone SE 2020. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone SE 2020 device](https://testingbot.com/assets/features/devices/apple-iphone-se-2020-9962d3c5453b4bc469a9e531ebb64ef18debfa80cedb2cab96a77b5808c66ffd.png) Trusted by some of the world's most innovative companies ## Automated Testing on an Apple iPhone SE 2020 ### Physical Apple iPhone SE 2020 Device Manual or automated testing, using Appium, XCUITest or Maestro, on a remote Apple iPhone SE 2020 simulator. ### Performance Testing Test the performance of your iOS app on iPhone SE 2020. Verify the speed of your app on an Apple iPhone SE 2020. ### Secure Each test runs on a brand new iOS Simulator, on a physical Mac. ### Test Various Network Speeds Run mobile tests with different network speeds on Apple iPhone SE 2020: choose between WiFi, 5G, 4G, Edge, and more. Test from various geolocations around the world. ## Apple iPhone SE 2020 Device Information - Display:4.7" - Camera:12MP - Memory:3GB RAM - Li-Ion Battery:1821mAh - iOS Supported Versions:iOS 13 up to iOS 16 - Processor:Apple A13 Bionic - Weight:148g, 7.3mm thickness - Resolution:750 x 1334 pixels, 16:9 ratio (~326 ppi density) - Dimensions:138.4 x 67.3 x 7.3 mm (5.45 x 2.65 x 0.29 in) [Test on iPhone SE 2020](https://testingbot.com/users/sign_up) ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-12-pro-max # Test on Apple iPhone 12 Pro Max Automated, manual and visual testing on Apple iPhone 12 Pro Max. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 12 Pro Max. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 12 Pro Max device](https://testingbot.com/assets/features/devices/apple-iphone-12-pro-max-a25e8645eeca21555ed41db8e7eec2135082d77b9399c91f28ba92b5b54842f4.png) Trusted by some of the world's most innovative companies ## Online Testing on an Apple iPhone 12 Pro Max ### Apple iPhone 12 Pro Max iOS Simulator Ready to run your Appium and XCUITests on a remote Apple iPhone 12 Pro Max simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 12 Pro Max. Check the speed of your app on an Apple iPhone 12 Pro Max simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 12 Pro Max. ### Tap, Swipe, Pinch & more Interact with a iPhone 12 Pro Max, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 12 Pro Max: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 12 Pro Max Device Information - Display:6.7" - Camera:12MP + 12MP + 12MP + LiDAR - Memory:6GB RAM - Li-Ion Battery:3687mAh - iOS Supported Versions:iOS 14.1 and higher - Processor:Apple A14 Bionic - Weight:228g, 7.4mm thickness - Resolution:1284 x 2778 pixels, 19.5:9 ratio (~458 ppi density) - Dimensions:160.8 x 78.1 x 7.4 mm (6.33 x 3.07 x 0.29 in) [Test on iPhone 12 Pro Max](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 12 Pro Max? TestingBot provides remote Apple iPhone 12 Pro Max simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 12 Pro Max. ### Do I still need to test on an Apple iPhone 12 Pro Max? Apple iPhone 12 Pro Max is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-12-pro # Test on Apple iPhone 12 Pro Automated, manual and visual testing on Apple iPhone 12 Pro. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 12 Pro. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 12 Pro device](https://testingbot.com/assets/features/devices/apple-iphone-12-pro-a537ebe0d0a4dcd08de9ae5635bb0aebc14e60772b53b7a714a3cbdb0ab0dc3a.png) Trusted by some of the world's most innovative companies ## Online Testing on an Apple iPhone 12 Pro ### Apple iPhone 12 Pro iOS Simulator Run your Appium and XCUITests on a remote Apple iPhone 12 Pro simulator, with audio. ### Performance Testing Test the performance of your iOS app on iPhone 12 Pro. Check the speed of your iOS app on an Apple iPhone 12 Pro simulator. ### Secure Each test runs on a new iOS Simulator, with realtime video and audio. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 12 Pro. ### Tap, Swipe, Pinch & more Interact with a iPhone 12 Pro, with your own mouse and keyboard. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 12 Pro: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 12 Pro Device Information - Display:6.1" - Camera:12MP + 12MP + 12MP + LiDAR - Memory:6GB RAM - Li-Ion Battery:2815mAh - iOS Supported Versions:iOS 14.1 and higher - Processor:Apple A14 Bionic - Weight:189g, 7.4mm thickness - Resolution:1170 x 2532 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:146.7 x 71.5 x 7.4 mm (5.78 x 2.81 x 0.29 in) [Test on iPhone 12 Pro](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 12 Pro? TestingBot provides remote Apple iPhone 12 Pro simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 12 Pro. ### Do I still need to test on an Apple iPhone 12 Pro? Apple iPhone 12 Pro is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-12 # Test on Apple iPhone 12 Automated, manual and visual testing on Apple iPhone 12. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 12. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 12 device](https://testingbot.com/assets/features/devices/apple-iphone-12-d4b6ea96a9750275b7be5fc74bd3a64191a1c22a9053375bc0da85d80ffc10aa.png) Trusted by some of the world's most innovative companies ## Automated and Manual testing on Apple iPhone 12 ### Physical Apple iPhone 12 Device Run Appium and XCUITests on a physical Apple iPhone 12 device, located in the TestingBot device lab. ### Performance Testing Realtime insights in the performance of your app, running on iPhone 12. Accelerate your mobile beta testing on Apple iPhone 12. ### Secure Every test runs on a cleanly wiped iPhone 12, without any jailbreaks or tweaks. ### Insights Receive crash reports from iOS, debug possible Swift or Objective-C errors and more on a remote device. ### Tap, Swipe, Pinch & more Tap, swipe, pinch and perform other gestures. Audio from the iPhone 12 device is streamed during interactive testing. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 12: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 12 Device Information - Display:6.1" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:2815mAh - iOS Supported Versions:iOS 14 up to iOS 16 - Processor:Apple A14 Bionic - Weight:164g, 7.4mm thickness - Resolution:1170 x 2532 pixels, 19.5:9 ratio (~460 ppi density) - Dimensions:146.7 x 71.5 x 7.4 mm (5.78 x 2.81 x 0.29 in) [Test on iPhone 12](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I inspect an element or debug a script online on iPhone 12? TestingBot provides interactive access to a remote Apple iPhone 12 device. Use your mouse and keyboard to take control of the device, swipe, tap and pinch. Using the official Safari Developer Tools, you can inspect elements on Apple iPhone 12, debug Javascript errors or view the network requests generated on the device. ### How can I do responsive testing on Apple iPhone 12? You can switch between portrait mode or landscape mode to test your website and native mobile app on iPhone 12. These are official Apple devices, which allow you to test your website and app for responsive issues, for example elements that are overlapping, or content that is too wide. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-12-mini # Test on Apple iPhone 12 Mini Automated, manual and visual testing on Apple iPhone 12 Mini. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 12 Mini. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 12 Mini device](https://testingbot.com/assets/features/devices/apple-iphone-12-mini-8a3197b0e06b8fb563dbd42867772bbed8025a56e53728054b558461d1ed09c0.png) Trusted by some of the world's most innovative companies ## Online Testing on an Apple iPhone 12 Mini ### Apple iPhone 12 Mini iOS Device Ready to run your Appium and XCUITests on a remote Apple iPhone 12 Mini simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 12 Mini. Check the speed of your app on an Apple iPhone 12 Mini simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 12 Mini. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 12 Mini: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 12 Mini Device Information - Display:5.4" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:2227mAh - iOS Supported Versions:iOS 14 up to iOS 16 - Processor:Apple A14 Bionic - Weight:133g, 7.4mm thickness - Resolution:1080 x 2340 pixels, 19.5:9 ratio (~476 ppi density) - Dimensions:131.5 x 64.2 x 7.4 mm (5.18 x 2.53 x 0.29 in) [Test on iPhone 12 Mini](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test with Appium on iPhone 12 Mini? TestingBot provides cloud access to Apple iPhone 12 Mini, capable of running Appium. Simply connect your existing or new Appium scripts to the TestingBot device farm, send the correct capabilities and your test will run on iPhone 12 Mini. ### Why should I test on an Apple iPhone 12 Mini? Apple iPhone 12 Mini is still used by a percentage of mobile phone users, it may be important to make sure your website and apps look good and function correctly on this type of device. Next to testing on Apple iPhone 12 Mini, it might also be good to test on similar models such as [iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) and [iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro). ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-11-pro-max # Test on Apple iPhone 11 Pro Max Automated, manual and visual testing on Apple iPhone 11 Pro Max. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 11 Pro Max. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 11 Pro Max device](https://testingbot.com/assets/features/devices/apple-iphone-11-pro-max-4fe742da5108dcc2f09fdc440d761ef815fb7a8f98fbbb397a32597d154b0904.png) Trusted by some of the world's most innovative companies ## Test on an Apple iPhone 11 Pro Max ### Apple iPhone 11 Pro Max iOS Simulator Ready to run your Appium and XCUITests on a remote Apple iPhone 11 Pro Max simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 11 Pro Max. Check the speed of your app on an Apple iPhone 11 Pro Max simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 11 Pro Max. ### Tap, Swipe, Pinch & more Interact with a iPhone 11 Pro Max, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 11 Pro Max: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 11 Pro Max Device Information - Display:6.5" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:3969mAh - iOS Supported Versions:iOS 13 up to iOS 15 - Processor:Apple A13 Bionic - Weight:226g, 8.1mm thickness - Resolution:1242 x 2688 pixels, 19.5:9 ratio (~458 ppi density) - Dimensions:158 x 77.8 x 8.1 mm (6.22 x 3.06 x 0.32 in) [Test on iPhone 11 Pro Max](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I test online on iPhone 11 Pro Max? TestingBot provides remote Apple iPhone 11 Pro Max simulators, capable of running automated, visual and manual tests. Log in to your TestingBot account to start testing on a iPhone 11 Pro Max. ### Do I still need to test on an Apple iPhone 11 Pro Max? Apple iPhone 11 Pro Max is still used by a (small) percentage of mobile phone users. Eventhough most users have moved to a more recent iPhone, it might still be worthwhile to make sure your website and apps look good and function correctly on this configuration. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-11-pro # Test on Apple iPhone 11 Pro Automated, manual and visual testing on Apple iPhone 11 Pro. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 11 Pro. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 11 Pro device](https://testingbot.com/assets/features/devices/apple-iphone-11-pro-6a79ff72aae7c36c73aa9712d8ba87c0227cb62fb99a750d7a2d356d7e58f302.png) Trusted by some of the world's most innovative companies ## Test on an Apple iPhone 11 Pro ### Apple iPhone 11 Pro iOS Simulator Run Appium and XCUITests automated tests on a remote Apple iPhone 11 Pro simulator. ### Performance Testing Test the performance of your iOS app on iPhone 11 Pro. Check the speed of your app on an Apple iPhone 11 Pro simulator. ### Secure Each test runs on a brand new iOS Simulator, optimised for testing. ### Insights Inspect crash reports and examine possible Swift or Objective-C errors on iPhone 11 Pro. ### Tap, Swipe, Pinch & more Interact with a iPhone 11 Pro from your own browser, with your mouse and keyboard. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 11 Pro: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 11 Pro Device Information - Display:5.8" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:3046mAh - iOS Supported Versions:iOS 13 up to iOS 15 - Processor:Apple A13 Bionic - Weight:188g, 8.1mm thickness - Resolution:1125 x 2436 pixels, 19.5:9 ratio (~458 ppi density) - Dimensions:144 x 71.4 x 8.1 mm (5.67 x 2.81 x 0.32 in) [Test on iPhone 11 Pro](https://testingbot.com/users/sign_up) ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-dabdb71f5311b879fa335264bdf358d1851d455ad79abf95eb0aab528d7c96f7.webp)](https://testingbot.com/mobile-testing/apple-iphone-11)[Apple iPhone 11](https://testingbot.com/mobile-testing/apple-iphone-11) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/mobile-testing/apple-iphone-11 # Test on Apple iPhone 11 Automated, manual and visual testing on Apple iPhone 11. Check if your website and mobile app works and looks correctly on a remote Apple iPhone 11. [Get started free](https://testingbot.com/users/sign_up)[Request a demo](https://testingbot.com/demo) ![Apple iPhone 11 device](https://testingbot.com/assets/features/devices/apple-iphone-11-2dc3201a4ddc63145544753f97697bb0d2abef492993b22a32e59f7769543e9c.png) Trusted by some of the world's most innovative companies ## Test on an Apple iPhone 11 ### Apple iPhone 11 iOS Simulator Ready to run your Appium and XCUITests on a remote Apple iPhone 11 simulator, optimised for testing. ### Performance Testing Performance testing of your iOS app on iPhone 11. Check the speed of your app on an Apple iPhone 11 simulator. ### Secure Every test runs on a brand new iOS Simulator, with secure access. ### Insights Debug crash reports, discover possible Swift or Objective-C errors on iPhone 11. ### Tap, Swipe, Pinch & more Interact with a iPhone 11, just like you would have it in your own hand. ### Test various network speeds Run mobile tests with different network speeds on Apple iPhone 11: choose between WiFi, 5G, 4G, Edge and more. Test from various geolocations around the world. ## Apple iPhone 11 Device Information - Display:6.1" - Camera:12MP - Memory:4GB RAM - Li-Ion Battery:3110mAh - iOS Supported Versions:iOS 13 up to iOS 15 - Processor:Apple A13 Bionic - Weight:194g, 8.3mm thickness - Resolution:828 x 1792 pixels, 19.5:9 ratio (~326 ppi density) - Dimensions:150.9 x 75.7 x 8.3 mm (5.94 x 2.98 x 0.33 in) [Test on iPhone 11](https://testingbot.com/users/sign_up) ## Frequently Asked Questions ### How can I inspect a DOM element in Mobile Safari on iPhone 11? TestingBot provides interactive access to a remote Apple iPhone 11 device. Each iPhone 11 device is connected for remote debugging with Safari Developer Tools. You can inspect elements straight from the TestingBot Manual test page. ### How can I do responsive testing on Apple iPhone 11? Switch between portrait mode or landscape mode to test your website and native mobile app on iPhone 11. These are official Apple devices, which allow you to test your website and app for responsive issues, for example elements that are overlapping, or content that is too wide. ## Other iOS devices available for testing on TestingBot - [![iPhone 17 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-pro-ef9617902d6fc9935cdf49f21eedd8629ebc678967934b8f225741324ed13053.webp)](https://testingbot.com/mobile-testing/apple-iphone-17-pro)[Apple iPhone 17 Pro](https://testingbot.com/mobile-testing/apple-iphone-17-pro) - [![iPhone 17](https://testingbot.com/assets/features/devices/webp/apple-iphone-17-f9096e2cfd968cc3e4d74051d2cc583c169c803212a8197f277a0ad4cac3aa6f.webp)](https://testingbot.com/mobile-testing/apple-iphone-17)[Apple iPhone 17](https://testingbot.com/mobile-testing/apple-iphone-17) - [![iPhone Air](https://testingbot.com/assets/features/devices/webp/apple-iphone-air-1098e7178db8baf782c1abe9147df79a1ad922a45ce72bcf57931ecc966132c4.webp)](https://testingbot.com/mobile-testing/apple-iphone-air)[Apple iPhone Air](https://testingbot.com/mobile-testing/apple-iphone-air) - [![iPhone 16](https://testingbot.com/assets/features/devices/webp/apple-iphone-16-ea69f4e798740d7a410c5d67c085728ed58242bf1ea9467dbda8ad7dbb6c3fd7.webp)](https://testingbot.com/mobile-testing/apple-iphone-16)[Apple iPhone 16](https://testingbot.com/mobile-testing/apple-iphone-16) - [![iPhone 15](https://testingbot.com/assets/features/devices/webp/apple-iphone-15-3cc88a4045e988f507f7b812a2ab61a3538d95e6ef90ec63ce6269104bf4ef12.webp)](https://testingbot.com/mobile-testing/apple-iphone-15)[Apple iPhone 15](https://testingbot.com/mobile-testing/apple-iphone-15) - [![iPhone 14 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-max-8b9c1fa6139b8a9263a68bebca076fd86afc2dd792c4ad0fdae64e4de47f6dd4.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max)[Apple iPhone 14 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-14-pro-max) - [![iPhone 14 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-pro-143c701a6c75984d879b1d4f36f6e3ddc5e9032d200031dbebb1287aadad0e99.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-pro)[Apple iPhone 14 Pro](https://testingbot.com/mobile-testing/apple-iphone-14-pro) - [![iPhone 14 Plus](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-plus-b259a9799fed192044193a7983889105866588da44f9f307717c83414e152c3b.webp)](https://testingbot.com/mobile-testing/apple-iphone-14-plus)[Apple iPhone 14 Plus](https://testingbot.com/mobile-testing/apple-iphone-14-plus) - [![iPhone 14](https://testingbot.com/assets/features/devices/webp/apple-iphone-14-86edf6be35572084b195312898d926cdd778b6ef679c838e66b5a4acb38a0bfd.webp)](https://testingbot.com/mobile-testing/apple-iphone-14)[Apple iPhone 14](https://testingbot.com/mobile-testing/apple-iphone-14) - [![iPhone SE (2022)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2022-8338fcf2fcc93f44bc7479dd16eb420ccd51dec9e921324ece2b057fd97b4b61.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2022)[Apple iPhone SE (2022)](https://testingbot.com/mobile-testing/apple-iphone-se-2022) - [![iPhone 13 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-max-f673adb5854abed3d8e6d2089f25c1fb5eba59a20df3c09add0322d515092817.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max)[Apple iPhone 13 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-13-pro-max) - [![iPhone 13 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-pro-42a138fafae661e32feadcecb902ea9849193de52c6a2d315c8320bbf1d0ca97.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-pro)[Apple iPhone 13 Pro](https://testingbot.com/mobile-testing/apple-iphone-13-pro) - [![iPhone 13](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-285d8c527f6d0f4e99c75f4c9bfe6d4ab41599607e459be43d2a9cb3ff5d07e4.webp)](https://testingbot.com/mobile-testing/apple-iphone-13)[Apple iPhone 13](https://testingbot.com/mobile-testing/apple-iphone-13) - [![iPhone 13 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-13-mini-f8fcbbc2533378f8c4cad1944da73992f6b3848896f183bdd3bfd64965a1787e.webp)](https://testingbot.com/mobile-testing/apple-iphone-13-mini)[Apple iPhone 13 Mini](https://testingbot.com/mobile-testing/apple-iphone-13-mini) - [![iPhone 12 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-max-34ddb531ddd3c3bed8538c6caa4cb471c043ec56e3c54d298c2639431587715c.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max)[Apple iPhone 12 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-12-pro-max) - [![iPhone 12 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-pro-48baa6f4884151e6cae9178e60ff15d872fbf1b1aed51de1b2c1019b1386eed8.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-pro)[Apple iPhone 12 Pro](https://testingbot.com/mobile-testing/apple-iphone-12-pro) - [![iPhone 12](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-566631941e0aff52225afe0176004839aa96bd7f10aa78e9cb8be34d7002fadf.webp)](https://testingbot.com/mobile-testing/apple-iphone-12)[Apple iPhone 12](https://testingbot.com/mobile-testing/apple-iphone-12) - [![iPhone 12 Mini](https://testingbot.com/assets/features/devices/webp/apple-iphone-12-mini-464a1f6ee6223651f04eca522702a4f760443353672326748ac8201e779e8a4f.webp)](https://testingbot.com/mobile-testing/apple-iphone-12-mini)[Apple iPhone 12 Mini](https://testingbot.com/mobile-testing/apple-iphone-12-mini) - [![iPhone SE (2020)](https://testingbot.com/assets/features/devices/webp/apple-iphone-se-2020-384ea815adcf31fb308d47133620e92be3c8ab367cfc4e51390cc1087c26bd9a.webp)](https://testingbot.com/mobile-testing/apple-iphone-se-2020)[Apple iPhone SE (2020)](https://testingbot.com/mobile-testing/apple-iphone-se-2020) - [![iPhone 11 Pro Max](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-max-a3e7aede1805e370ddc044716489c3461b847455b30cd225cd27944daffdcff8.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max)[Apple iPhone 11 Pro Max](https://testingbot.com/mobile-testing/apple-iphone-11-pro-max) - [![iPhone 11 Pro](https://testingbot.com/assets/features/devices/webp/apple-iphone-11-pro-96e877df12c42057fd8b342555696852eed8775d856415c834e90af7c8e7c773.webp)](https://testingbot.com/mobile-testing/apple-iphone-11-pro)[Apple iPhone 11 Pro](https://testingbot.com/mobile-testing/apple-iphone-11-pro) ### Sign up for a Free Trial [Start a free trial](https://testingbot.com/users/sign_up) --- URL: https://testingbot.com/software-testing-questions # Automated Testing Questions Get answers to the most frequently asked questions related to test automation, mobile testing and QA in general. ### [What are all the Chrome Command Line Switches?](https://testingbot.com/software-testing-questions/chrome-command-line-switches) ### [How to test on Safari with Windows?](https://testingbot.com/software-testing-questions/download-safari-windows) ### [Handling Puppeteer performance issues](https://testingbot.com/software-testing-questions/how-to-handle-puppeteer-performance-issues) ### [What is a test-suite for Testing?](https://testingbot.com/software-testing-questions/what-is-a-test-suite) ### [What is Geolocation Testing?](https://testingbot.com/software-testing-questions/what-is-geolocation-testing) ### [What is an online browser sandbox?](https://testingbot.com/software-testing-questions/what-is-an-online-browser-sandbox) ### [What is a remote browser?](https://testingbot.com/software-testing-questions/what-is-a-remote-browser) ### [What is an uncensored Browser?](https://testingbot.com/software-testing-questions/what-is-an-uncensored-browser) ### [Learn about the difference between an Alert and a Popup](https://testingbot.com/software-testing-questions/what-is-the-difference-between-an-alert-and-a-popup) ### [Automated captcha solver for Selenium, Playwright and Puppeteer.](https://testingbot.com/software-testing-questions/how-to-solve-captchas-with-selenium-playwright) ### [Learn about Adhoc Testing](https://testingbot.com/software-testing-questions/what-is-adhoc-testing) ### [Retrieving attribute values when using Jest.](https://testingbot.com/software-testing-questions/how-to-get-attribute-value-of-an-element-using-jest) ### [How can I prevent the built-in dictionary from showing up on MacOS?](https://testingbot.com/software-testing-questions/how-to-stop-the-dictionary-from-popping-up-on-mac) ### [Which video output formats are compatible with WebM?](https://testingbot.com/software-testing-questions/webm-compatible-formats) ### [How to move an image in HTML?](https://testingbot.com/software-testing-questions/move-image-in-html) ### [How can I check my Screen Resolution?](https://testingbot.com/software-testing-questions/how-to-check-my-screen-resolution) ### [What is Chromedriver?](https://testingbot.com/software-testing-questions/what-is-chromedriver) ### [How to Center an Image in HTML?](https://testingbot.com/software-testing-questions/how-to-center-an-image-in-html) ### [What is Regression Testing?](https://testingbot.com/software-testing-questions/what-is-regression-testing) ### [How to update Safari on an old Mac?](https://testingbot.com/software-testing-questions/how-to-update-safari-on-an-old-mac) ### [Using FakerJS to generate Fake Data](https://testingbot.com/software-testing-questions/how-to-generate-fake-data) ### [What is an iOS device?](https://testingbot.com/software-testing-questions/what-is-an-ios-device) ### [Change timezone on macOS](https://testingbot.com/software-testing-questions/how-to-change-your-time-zone-on-mac) ### [What is White Box Testing?](https://testingbot.com/software-testing-questions/what-is-white-box-testing) ### [How to test Cypress on different browsers and devices?](https://testingbot.com/software-testing-questions/how-to-test-cypress-on-different-browsers-and-devices) ### [How to check the screen resolution on Android?](https://testingbot.com/software-testing-questions/how-to-check-screen-resolution-on-android) ### [How to view source code in Safari?](https://testingbot.com/software-testing-questions/how-to-view-source-code-in-safari) ### [How to configure a proxy for Automated Testing?](https://testingbot.com/software-testing-questions/how-to-use-a-proxy-for-automated-testing) ### [What is a browser window?](https://testingbot.com/software-testing-questions/what-is-a-browser-window) ### [Why are Selenium tests running slow or timing out?](https://testingbot.com/software-testing-questions/why-are-selenium-tests-running-slow-or-timing-out) ### [What is Keyword Driven Testing?](https://testingbot.com/software-testing-questions/what-is-keyword-driven-testing) ### [What is Chrome for Testing?](https://testingbot.com/software-testing-questions/what-is-chrome-for-testing) ### [What is Chromium?](https://testingbot.com/software-testing-questions/what-is-chromium) ### [How can I run an APK file on Windows?](https://testingbot.com/software-testing-questions/how-to-run-an-apk-on-windows) ### [What are best practices when using Selenium?](https://testingbot.com/software-testing-questions/what-are-some-best-practices-for-using-selenium-in-testing) ### [Why is cross-browser testing important?](https://testingbot.com/software-testing-questions/why-does-my-website-look-different-on-different-browsers) ### [What are TestNG listeners?](https://testingbot.com/software-testing-questions/what-are-testng-listeners) ### [How do I create a test plan?](https://testingbot.com/software-testing-questions/how-to-create-a-test-plan) ### [How can I inspect on Chrome?](https://testingbot.com/software-testing-questions/how-to-inspect-on-chrome) ### [What is a Selenium Grid?](https://testingbot.com/software-testing-questions/what-is-selenium-grid) ### [What is Selenium WebDriver?](https://testingbot.com/software-testing-questions/what-is-selenium-webdriver) ### [What is Behavior-Driven Development Testing?](https://testingbot.com/software-testing-questions/what-is-bdd-testing) ### [What is Shift-Left Testing?](https://testingbot.com/software-testing-questions/what-is-shift-left-testing) ### [What is Jest testing?](https://testingbot.com/software-testing-questions/what-is-jest-testing) ### [What is Gherkin?](https://testingbot.com/software-testing-questions/what-is-gherkin) ### [What is a Proxy for Testing?](https://testingbot.com/software-testing-questions/what-is-a-proxy-for-testing) --- URL: https://testingbot.com/support/accessibility/web/rules/area-alt # Ensure \ elements of image maps have alternative text Rule ID: area-altUser Impact: criticalGuidelines: WCAG 2.0 When using an image map, ensure that each clickable \ within the map has an `alt`, `aria-label` or `aria-labelledby` attribute to describe the purpose of the link. This ensures the map is accessible to screen readers and provides meaningful information about each link. ## How to fix this issue? An image map is identified by an ![]() element with a usemap attribute, pointing to a \ tag that defines clickable hotspots using elements. Each \ should include an alt attribute to describe its purpose. Solar System Mercury Venus ## Why you should fix this accessibility issue Screen readers cannot interpret or describe images visually. To make images, including image maps, accessible, it is crucial to provide meaningful alt text for each one. When `alt` text is missing, screen readers often announce the image's filename instead. Filenames rarely provide a clear or useful description of the image, leaving screen reader users without meaningful context. Providing descriptive alt text ensures that all users, including those relying on assistive technologies can understand the purpose and content of the image. ## Rule Description An image map is a single image containing multiple clickable areas. To ensure accessibility, each clickable area within the image map must have descriptive alternative text. Additionally, the larger image itself should include alternate text, as screen readers cannot interpret graphical content as text. Providing meaningful text descriptions ensures all users can understand and interact with the image map effectively. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-allowed-attr](https://testingbot.com/support/accessibility/web/rules/aria-allowed-attr) - [aria-braille-equivalent](https://testingbot.com/support/accessibility/web/rules/aria-braille-equivalent) - [aria-command-name](https://testingbot.com/support/accessibility/web/rules/aria-command-name) - [aria-conditional-attr](https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr) - [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-allowed-attr # Ensure an element's role supports its ARIA attributes Rule ID: aria-allowed-attrUser Impact: seriousGuidelines: WCAG 2.0 ## Understanding ARIA Attributes and Roles ARIA (Accessible Rich Internet Applications) defines specific roles and attributes to enhance accessibility. Each ARIA role has a set of permitted attributes, and every attribute specifies where and how it can be used. Detailed guidance on these relationships can be found in the documentation for individual roles and attributes. ### Specific Reference: For precise rules on how ARIA attributes can or should not be used with HTML elements, refer to: - [ARIA in HTML - Document Conformance Requirements](https://www.w3.org/TR/html-aria/#docconformance): Explains proper usage of ARIA attributes within HTML. - [ARIA in HTML - Naming Elements](https://www.w3.org/TR/html-aria/#docconformance-naming): Details requirements for using ARIA attributes to name elements. ### General Reference: For broader insights into ARIA and its implementation: - [WAI-ARIA Overview](https://www.w3.org/WAI/intro/aria.php): Provides an introduction to ARIA and its purpose. - [WAI-ARIA 1.1](https://www.w3.org/TR/wai-aria-1.1/): Outlines the technical specifications for ARIA. - [WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices/): Offers practical advice for implementing ARIA effectively. ## Why you should fix this accessibility issue Improper use of ARIA attributes, such as applying them to roles where they are not allowed, can negatively impact the accessibility of a web page. At best, invalid role-attribute combinations will have no effect on accessibility. At worst, they may cause behavior that disrupts or disables accessibility for significant portions of the application. When ARIA attributes are applied to HTML elements in ways that conflict with the WAI-ARIA 1.1 specification, they can interfere with the native semantics of those elements. This can lead assistive technologies to provide misleading or nonsensical information about the user interface, misrepresenting the actual structure and functionality of the document. ## Rule Description Not all ARIA role-attribute combinations are valid. This rule ensures that each ARIA role is accompanied only by attributes that are permitted for that role. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-braille-equivalent](https://testingbot.com/support/accessibility/web/rules/aria-braille-equivalent) - [aria-command-name](https://testingbot.com/support/accessibility/web/rules/aria-command-name) - [aria-conditional-attr](https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr) - [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) - [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-braille-equivalent # Make sure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent Rule ID: aria-braille-equivalentUser Impact: seriousGuidelines: WCAG 2.0 The `aria-braillelabel` and `aria-brailleroledescription` attributes are used to provide braille-specific labels and descriptions for assistive technologies. Misplacing or misusing these attributes can lead to accessibility issues. Follow these guidelines to ensure proper implementation: ## 1. Correct Element Placement Ensure that the `aria-braillelabel` or `aria-brailleroledescription` attributes are applied directly to the correct element, not to its parent or child. **Correct:** ` ` **Incorrect:** `
` ## 2. Requirements for aria-braillelabel When using the `aria-braillelabel` attribute, the element must also have an accessible name provided by an `aria-label` or another naming attribute. **Correct:** ` 📁 Download ` **Incorrect:** ` 📁 Download ` ## 3. Requirements for aria-brailleroledescription When using the `aria-brailleroledescription` attribute, ensure the element also has an `aria-roledescription` attribute to provide context for its role. **Correct:** `
Menu
` **Incorrect:** `
Menu
` ## 4. Remove Unnecessary Attributes If the `aria-braillelabel` or `aria-brailleroledescription` attribute does not serve a clear purpose or is misused, it should be removed to maintain clarity and functionality. **Correct:** `
Menu
` **Incorrect:** `
Menu
` ## Common Mistakes to Avoid - Using `aria-braillelabel` without an `aria-label` or similar naming attribute. - Using `aria-brailleroledescription` without an `aria-roledescription`. **Warning:** Failing to provide corresponding attributes can result in these ARIA braille attributes being ignored or, worse, causing confusion in assistive technologies. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-command-name](https://testingbot.com/support/accessibility/web/rules/aria-command-name) - [aria-conditional-attr](https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr) - [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) - [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) - [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-command-name # ARIA commands must have an accessible name Rule ID: aria-command-nameUser Impact: seriousGuidelines: WCAG 2.0 The aria-command-name problem occurs when interactive elements (e.g., buttons, links, menus) are not assigned a valid ARIA role or when custom ARIA attributes are used incorrectly. This can lead to assistive technologies misinterpreting or ignoring these elements, reducing accessibility. For example screen readers are not able to discern the purpose of elements with role="link", role="button" or role="menuitem" that do not have an accessible name. Always use native HTML elements with their built-in accessibility features wherever possible. When custom elements are necessary, make sure they have proper ARIA roles, valid attributes and accessible names. Here is how you can fix issues related to `aria-command-name`: ### Ensure Proper Use of ARIA Roles - Verify that interactive elements like buttons and links have appropriate ARIA roles. Use `role="button"` for a custom button or `role="link"` for a custom hyperlink. - Avoid unnecessary ARIA roles when native HTML semantics suffice. For example, use `>button>` instead of `
`. ### Provide Accessible Names Make sure every interactive element has an accessible name that clearly describes its purpose, by using the `aria-label` or `aria-labelledby` attributes. ### Use ARIA Attributes Correctly - Use only valid ARIA attributes appropriate to the assigned role. - Avoid non-standard ARIA attributes like `aria-command-name`, as they might not be supported. - Consult the [WAI-ARIA specification](https://www.w3.org/TR/wai-aria/) for the correct attributes for each role. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-conditional-attr](https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr) - [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) - [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) - [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) - [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-conditional-attr # Ensure ARIA attributes are used as described in the specification of the element's role Rule ID: aria-conditional-attrUser Impact: seriousGuidelines: WCAG 2.0 Using ARIA attributes on elements where they are not intended can cause unpredictable behavior in assistive technologies. This could result in a poor user experience for individuals with disabilities who depend on these tools. Adhering to the ARIA specification is crucial to ensure assistive technologies can accurately interpret and convey the intended meaning of the content. ## Why It Matters Using ARIA attributes in unexpected ways can cause confusing behavior for assistive technologies. Adhering to ARIA specifications ensures that individuals with disabilities can effectively interpret and interact with web content. ## How to Fix For checkboxes, consider the following approaches: - Remove the `aria-checked` attribute from native HTML checkboxes and manage their state using the `indeterminate` property. - If replacing the native checkbox with a custom element, ensure it has the appropriate role and is keyboard accessible. For `tr` elements with a role of `row`, you may need to change the role of the parent `table` or `grid` to `treegrid`. ### Example #### Fail The following example incorrectly uses the `aria-checked` attribute on a native checkbox, and the `row` elements are part of a `table` instead of a `treegrid`:
...
...
...
#### Pass In this corrected example, the `aria-checked` attribute is removed from the native checkbox, and the parent element is correctly set to `treegrid` for the `row` elements:
...
...
...
## About This Rule This rule passes under the following conditions: - For `aria-checked`: - It is not used on an HTML `input` element of type `checkbox`. - Browsers ignore `aria-checked` on native checkboxes. - For `row` elements: - Attributes like `aria-posinset`, `aria-setsize`, `aria-expanded`, and `aria-level` are used only when the `row` is part of a `treegrid`. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-deprecated-role](https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role) - [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) - [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) - [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) - [aria-meter-name](https://testingbot.com/support/accessibility/web/rules/aria-meter-name) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-deprecated-role # Make sure elements do not use deprecated roles Rule ID: aria-deprecated-roleUser Impact: minorGuidelines: WCAG 2.0 ## About This A11Y Rule This rule ensures that ARIA role attributes do not use deprecated or abstract values. Deprecated roles are those that the ARIA specification no longer recommends. Abstract roles are intended for user agent implementation and must not be used by web developers. ## Why It Matters Using deprecated ARIA roles can cause elements to be unrecognized by assistive technologies, leading to accessibility issues. This may prevent users from accessing essential information. ## How to Fix Replace deprecated roles with their modern equivalents. For example, use the `list` role instead of the deprecated `directory` role. ### Example #### Fail The following example uses the deprecated `directory` role:
...
#### Pass In this corrected example, the valid `list` role is used:
...
## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-hidden-body](https://testingbot.com/support/accessibility/web/rules/aria-hidden-body) - [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) - [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) - [aria-meter-name](https://testingbot.com/support/accessibility/web/rules/aria-meter-name) - [aria-progressbar-name](https://testingbot.com/support/accessibility/web/rules/aria-progressbar-name) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-hidden-body # Make sure aria-hidden="true" is not present on the document body. Rule ID: aria-hidden-bodyUser Impact: criticalGuidelines: WCAG 2.0 The attribute `aria-hidden="true"` must not be used on the `` element. ## About This Rule This rule ensures that the `` element does not have the `aria-hidden` attribute, maintaining accessibility for assistive technologies. ## Why It Matters Applying `aria-hidden="true"` to the `` element hides all its content from assistive technologies, such as screen readers. While users can still navigate to focusable elements using the keyboard, the content remains inaccessible, leading to a poor user experience for individuals relying on these technologies. ## How to Fix - Remove `aria-hidden="true"` from the `` element. - Apply `aria-hidden="true"` only to elements whose content is decorative or redundant for assistive technology users. - Avoid using `aria-hidden="false"` on child elements of a parent with `aria-hidden="true"`, as it won't make them visible to assistive technologies. ### Example #### Fail In this example, `aria-hidden="true"` is incorrectly applied to the `` element, hiding all content from assistive technologies: ... ... #### Pass The attribute `aria-hidden="true"` must never applied to the `` element. Instead, when a dialog is open, elements outside the dialog can be removed from the tab order. ... ... ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-hidden-focus](https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus) - [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) - [aria-meter-name](https://testingbot.com/support/accessibility/web/rules/aria-meter-name) - [aria-progressbar-name](https://testingbot.com/support/accessibility/web/rules/aria-progressbar-name) - [aria-prohibited-attr](https://testingbot.com/support/accessibility/web/rules/aria-prohibited-attr) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-hidden-focus # Ensure aria-hidden elements are not focusable nor contain focusable elements Rule ID: aria-hidden-focusUser Impact: seriousGuidelines: WCAG 2.0 ## Why It Matters Applying `aria-hidden="true"` to an element hides it and all its children from assistive technologies, such as screen readers. However, users can still navigate to any focusable child elements using the keyboard. This discrepancy means that while these elements are focusable, their content remains inaccessible to assistive technology users, leading to confusion and a poor user experience. ## About This Rule This rule ensures that elements with `aria-hidden="true"` do not contain focusable elements. It passes if any of the following are true: - The element with `aria-hidden="true"` contains no focusable elements. - The element with `aria-hidden="true"` contains only focusable elements that are disabled or not tabbable. ## How to Fix - Use `aria-hidden="true"` only on elements whose content is decorative or redundant for assistive technology users. - Restructure the code so that focusable elements are not children of an element with `aria-hidden="true"`. - Make child elements non-focusable by applying the `disabled` attribute or non-tabbable by setting `tabindex="-1"`. - Where appropriate, hide elements from all users by applying the `hidden` attribute or using CSS properties like `display: none;` or `visibility: hidden;`. ### Example #### Fail An alert is positioned off-screen and marked with `aria-hidden="true"` until it’s needed. However, the alert contains an OK button that remains focusable even when the alert is hidden. Keyboard users can tab to the button but cannot discern its purpose. #### Pass When the alert is positioned off-screen, its OK button is marked with `tabindex="-1"`. Keyboard users encounter the button only when the alert is on-screen. ## Other Rules Interested in other web accessibility rules? Please see these other rules: - [aria-input-field-name](https://testingbot.com/support/accessibility/web/rules/aria-input-field-name) - [aria-meter-name](https://testingbot.com/support/accessibility/web/rules/aria-meter-name) - [aria-progressbar-name](https://testingbot.com/support/accessibility/web/rules/aria-progressbar-name) - [aria-prohibited-attr](https://testingbot.com/support/accessibility/web/rules/aria-prohibited-attr) - [aria-required-attr](https://testingbot.com/support/accessibility/web/rules/aria-required-attr) --- URL: https://testingbot.com/support/accessibility/web/rules/aria-input-field-name # Ensure every ARIA input field has an accessible name Rule ID: aria-input-field-nameUser Impact: seriousGuidelines: WCAG 2.0 ARIA input fields must have accessible names. ## About This Rule This rule passes if any of the following are true: - The element has an `aria-labelledby` attribute that references elements visible to screen readers. - The element has a non-empty `aria-label` attribute. - The element has a non-empty `title` attribute. There should be no mismatch between the element's `