Azure DevOps Cloud Testing Integration
How to integrate Azure DevOps with cloud testing platforms — BrowserStack, Sauce Labs, and LambdaTest. Covers service connection setup, pipeline YAML for.
Cloud testing platforms give your Azure DevOps pipeline access to thousands of real browsers and devices without managing any infrastructure. This guide covers integration with BrowserStack, Sauce Labs, and LambdaTest.
Why cloud testing platforms with Azure DevOps
Microsoft-hosted agents provide Chrome and Firefox. For comprehensive cross-browser and mobile testing you need real Safari on iOS, real Android devices, older browser versions, and specific OS combinations. Cloud platforms provide all of this on demand.
BrowserStack integration
Service connection setup
- Go to Project Settings → Service connections → New
- Type: BrowserStack (from Marketplace extension)
- Enter: BrowserStack username and access key
Or use a generic service connection and reference credentials via variable group.
Pipeline YAML — Playwright on BrowserStack
YAML1trigger: 2 branches: 3 include: [main] 4 5pool: 6 vmImage: ubuntu-latest 7 8variables: 9 - group: browserstack-credentials 10 11steps: 12 - task: NodeTool@0 13 inputs: 14 versionSpec: '20.x' 15 16 - script: npm ci 17 displayName: Install packages 18 19 - script: npm install -g browserstack-local 20 displayName: Install BrowserStack Local 21 22 - script: | 23 # Start BrowserStack Local tunnel for staging (non-public) environments 24 BrowserStackLocal --key $(BROWSERSTACK_KEY) \ 25 --local-identifier $(Build.BuildId) & 26 sleep 5 27 displayName: Start local tunnel 28 condition: eq(variables['STAGING_IS_LOCAL'], 'true') 29 30 - script: | 31 npx playwright test \ 32 --config=playwright.browserstack.config.ts 33 displayName: Run tests on BrowserStack 34 env: 35 BROWSERSTACK_USERNAME: $(BROWSERSTACK_USERNAME) 36 BROWSERSTACK_ACCESS_KEY: $(BROWSERSTACK_KEY) 37 BUILD_NAME: $(Build.BuildNumber) 38 BUILD_ID: $(Build.BuildId) 39 40 - task: PublishTestResults@2 41 inputs: 42 testResultsFormat: JUnit 43 testResultsFiles: test-results/browserstack.xml 44 testRunTitle: BrowserStack — $(Build.BuildNumber) 45 condition: always()
Playwright BrowserStack config
TYPESCRIPT1// playwright.browserstack.config.ts 2import { defineConfig } from '@playwright/test' 3 4export default defineConfig({ 5 reporter: [ 6 ['junit', { outputFile: 'test-results/browserstack.xml' }], 7 ['html'], 8 ], 9 projects: [ 10 { 11 name: 'Chrome/Windows10', 12 use: { 13 connectOptions: { 14 wsEndpoint: `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify({ 15 browser: 'chrome', 16 browser_version: 'latest', 17 os: 'Windows', 18 os_version: '10', 19 name: 'Chrome Windows 10', 20 build: process.env.BUILD_NAME, 21 'browserstack.username': process.env.BROWSERSTACK_USERNAME, 22 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, 23 }))}`, 24 }, 25 }, 26 }, 27 { 28 name: 'Safari/macOS13', 29 use: { 30 connectOptions: { 31 wsEndpoint: `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify({ 32 browser: 'playwright-webkit', 33 os: 'OS X', 34 os_version: 'Ventura', 35 name: 'Safari macOS Ventura', 36 build: process.env.BUILD_NAME, 37 'browserstack.username': process.env.BROWSERSTACK_USERNAME, 38 'browserstack.accessKey': process.env.BROWSERSTACK_ACCESS_KEY, 39 }))}`, 40 }, 41 }, 42 }, 43 ], 44})
Sauce Labs integration
YAML1steps: 2 - script: npm ci 3 4 - script: | 5 npx playwright test \ 6 --config=playwright.saucelabs.config.ts 7 env: 8 SAUCE_USERNAME: $(SAUCE_USERNAME) 9 SAUCE_ACCESS_KEY: $(SAUCE_ACCESS_KEY)
TYPESCRIPT1// playwright.saucelabs.config.ts 2export default defineConfig({ 3 projects: [{ 4 name: 'Sauce Chrome', 5 use: { 6 connectOptions: { 7 wsEndpoint: `wss://ondemand.us-west-1.saucelabs.com/wd/hub?username=${process.env.SAUCE_USERNAME}&access_key=${process.env.SAUCE_ACCESS_KEY}`, 8 }, 9 }, 10 }], 11})
LambdaTest integration
YAML1steps: 2 - script: | 3 npx playwright test \ 4 --config=playwright.lambdatest.config.ts 5 env: 6 LT_USERNAME: $(LT_USERNAME) 7 LT_ACCESS_KEY: $(LT_ACCESS_KEY)
Cost optimisation strategies
Cloud platforms charge per test minute. Keep costs manageable:
YAML1# Run cloud tests only on main branch merges, not every PR 2- stage: CloudBrowserTests 3 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) 4 jobs: 5 - job: BrowserStack 6 steps: 7 # Run only smoke tests on cloud — full regression locally 8 - script: npx playwright test --grep @cross-browser
YAML1# Limit parallel sessions to control costs 2# In playwright.browserstack.config.ts: 3workers: 3, # BrowserStack free tier: 5 parallel sessions — use 3 for safety
Common errors and fixes
Error: BrowserStack tests fail with "Authentication failed"
Fix: Verify BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY are set correctly. The username is your email address, not a generated string.
Error: Tests connect but can't reach the staging URL Fix: If staging is not publicly accessible, start the BrowserStack Local tunnel before running tests. The tunnel creates a secure connection between BrowserStack's nodes and your private environment.
Error: Test results don't appear on BrowserStack dashboard
Fix: Include build and name in the capabilities object. Without these, BrowserStack creates sessions with auto-generated names that don't correlate to your pipeline runs.
Share this article
Follow for more
Follow me on social media for more developer tips, tricks, and tutorials. Let's connect and build something great together!