BrowserStack
La plateforme cloud de test cross-browser et multi-device qui permet de tester des applications web et mobiles sur plus de 3000 navigateurs, appareils et systèmes d'exploitation réels.
Qu'est-ce que BrowserStack ?
Imaginez que vous créez un site web ou une application mobile et que vous devez vous assurer qu'elle fonctionne parfaitement pour tous vos utilisateurs, quel que soit leur appareil ou navigateur. C'est un défi considérable car il existe des centaines de combinaisons différentes de navigateurs, d'appareils et de systèmes d'exploitation. C'est là qu'intervient BrowserStack.
BrowserStack est comme un laboratoire virtuel géant qui vous donne accès instantanément à des milliers d'appareils et navigateurs réels via le cloud. Au lieu d'avoir à acheter et maintenir des dizaines d'appareils différents, vous pouvez simplement vous connecter à BrowserStack et tester votre site ou application sur n'importe quel appareil, comme si vous l'aviez physiquement entre les mains.
Ce que BrowserStack apporte à votre projet
Compatibilité universelle
La confiance que votre site ou application fonctionne correctement pour tous vos utilisateurs, quel que soit leur appareil ou navigateur, évitant ainsi les problèmes de compatibilité qui pourraient frustrer vos clients.
Économies substantielles
Élimination du besoin d'acheter et de maintenir un laboratoire coûteux d'appareils physiques, tout en permettant à votre équipe de tester sur une gamme beaucoup plus large d'environnements.
Tests automatisés
Possibilité d'automatiser les tests sur de multiples navigateurs et appareils simultanément, accélérant considérablement le cycle de développement et permettant des livraisons plus rapides et plus fiables.
Tests locaux et en interne
Capacité à tester des applications en développement ou des sites internes qui ne sont pas accessibles publiquement, grâce à des tunnels sécurisés entre votre environnement local et BrowserStack.
En somme, BrowserStack permet aux équipes de développement de livrer des applications web et mobiles de haute qualité, compatibles avec tous les environnements utilisateurs, tout en réduisant considérablement les coûts et les délais liés aux tests. C'est un outil essentiel pour toute entreprise soucieuse de l'expérience utilisateur de ses produits digitaux.
Fonctionnement technique
BrowserStack est une plateforme cloud de test qui permet aux développeurs de tester leurs sites web et applications sur des milliers de navigateurs, systèmes d'exploitation et appareils réels. Elle offre plusieurs produits complémentaires pour répondre à différents besoins de test.
Produits principaux
BrowserStack propose quatre produits principaux :
- Live - Test manuel sur des navigateurs et appareils réels
- Automate - Tests automatisés pour applications web avec Selenium et Cypress
- App Live - Test manuel d'applications mobiles natives
- App Automate - Tests automatisés d'applications mobiles avec Appium
Exemples pratiques d'intégration
Selenium avec BrowserStack Automate
Voici un exemple d'intégration de Selenium WebDriver avec BrowserStack pour des tests cross-browser automatisés :
// tests/e2e/crossbrowser.test.js
const { Builder, By, Key, until } = require('selenium-webdriver');
const assert = require('assert');
// Configuration des navigateurs et appareils à tester
const configurations = [
{
os: 'Windows',
osVersion: '10',
browser: 'Chrome',
browserVersion: 'latest',
name: 'Test sur Chrome Windows 10'
},
{
os: 'OS X',
osVersion: 'Big Sur',
browser: 'Safari',
browserVersion: 'latest',
name: 'Test sur Safari macOS Big Sur'
},
{
os: 'iOS',
osVersion: '15',
device: 'iPhone 13 Pro',
realMobile: true,
name: 'Test sur iPhone 13 Pro'
},
{
os: 'Android',
osVersion: '12.0',
device: 'Samsung Galaxy S22',
realMobile: true,
name: 'Test sur Samsung Galaxy S22'
}
];
async function runTest(capabilities) {
// Ajout des identifiants BrowserStack
const browserstackOptions = {
'browserstack.user': process.env.BROWSERSTACK_USERNAME,
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
'browserstack.debug': true, // Active les captures d'écran et les logs visuels
'browserstack.console': 'verbose',
'browserstack.networkLogs': true,
...capabilities
};
const driver = await new Builder()
.usingServer('https://hub-cloud.browserstack.com/wd/hub')
.withCapabilities(browserstackOptions)
.build();
try {
console.log(`Démarrage du test sur ${capabilities.name}`);
// Test de connexion (exemple)
await driver.get('https://example.com/login');
// Attendre que la page soit chargée
await driver.wait(until.elementLocated(By.id('login-form')), 10000);
// Remplir le formulaire de connexion
await driver.findElement(By.id('email')).sendKeys('test@example.com');
await driver.findElement(By.id('password')).sendKeys('password123', Key.RETURN);
// Attendre la redirection vers le tableau de bord
await driver.wait(until.urlContains('dashboard'), 10000);
// Vérifier que l'utilisateur est connecté
const welcomeElement = await driver.findElement(By.css('.welcome-message'));
const welcomeText = await welcomeElement.getText();
assert.ok(welcomeText.includes('Bienvenue'), 'Le message de bienvenue devrait être affiché');
console.log(`Test réussi sur ${capabilities.name}`);
// Marquer le test comme réussi sur BrowserStack
await driver.executeScript(
'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": "Login successful!"}}'
);
} catch (error) {
console.error(`Erreur sur ${capabilities.name}:`, error);
// Marquer le test comme échoué sur BrowserStack
await driver.executeScript(
`browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": "${error.message}"}}`
);
throw error;
} finally {
await driver.quit();
}
}
// Exécuter les tests sur tous les navigateurs/appareils configurés
describe('Tests cross-browser avec BrowserStack', function() {
// Augmenter le timeout pour les tests sur appareils réels
this.timeout(30 * 60 * 1000); // 30 minutes
for (const config of configurations) {
it(`devrait fonctionner sur ${config.name}`, async function() {
await runTest(config);
});
}
});
BrowserStack Local
Pour tester des applications en développement ou des environnements internes, BrowserStack Local établit un tunnel sécurisé :
// setup/browserstack-local.js
const browserstack = require('browserstack-local');
// Initialiser une instance de BrowserStack Local
const bsLocal = new browserstack.Local();
// Options pour BrowserStack Local
const localOptions = {
key: process.env.BROWSERSTACK_ACCESS_KEY,
verbose: true,
force: true, // Force la connexion même si elle est déjà établie
onlyAutomate: true, // Limite l'accès aux tests automatisés uniquement
forceLocal: true, // Force le trafic à passer par le tunnel local
localIdentifier: 'MyApp_' + Math.random().toString(36).substring(2, 8) // Identifiant unique pour le tunnel
};
// Démarrer BrowserStack Local avant les tests
async function startBrowserStackLocal() {
return new Promise((resolve, reject) => {
console.log('Démarrage de BrowserStack Local...');
bsLocal.start(localOptions, (error) => {
if (error) {
console.error('Erreur lors du démarrage de BrowserStack Local:', error);
return reject(error);
}
console.log('BrowserStack Local démarré avec succès!');
resolve();
});
});
}
// Arrêter BrowserStack Local après les tests
async function stopBrowserStackLocal() {
return new Promise((resolve, reject) => {
console.log('Arrêt de BrowserStack Local...');
bsLocal.stop((error) => {
if (error) {
console.error('Erreur lors de l'arrêt de BrowserStack Local:', error);
return reject(error);
}
console.log('BrowserStack Local arrêté avec succès!');
resolve();
});
});
}
// Vérifier si BrowserStack Local est en cours d'exécution
function isRunning() {
return bsLocal.isRunning();
}
module.exports = {
startBrowserStackLocal,
stopBrowserStackLocal,
isRunning
};
// Usage dans mocha.js hooks ou jest globalSetup/globalTeardown
//
// Dans un fichier mocha global hooks:
//
// const bsLocal = require('./browserstack-local');
//
// before(async function() {
// this.timeout(30000);
// await bsLocal.startBrowserStackLocal();
// });
//
// after(async function() {
// this.timeout(30000);
// await bsLocal.stopBrowserStackLocal();
// });
Cypress avec BrowserStack
BrowserStack prend également en charge les tests Cypress pour les applications web modernes :
// cypress.config.js
const { defineConfig } = require('cypress');
module.exports = defineConfig({
e2e: {
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
screenshotsFolder: 'cypress/screenshots',
supportFile: 'cypress/support/e2e.js'
},
// Configuration pour BrowserStack
reporter: 'mochawesome',
reporterOptions: {
reportDir: 'cypress/reports',
overwrite: false,
html: true,
json: true
},
// Variables d'environnement spécifiques à BrowserStack
env: {
browserstack: true
}
});
// cypress/browserstack.js
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');
const FormData = require('form-data');
// Configuration de l'intégration BrowserStack
const BROWSERSTACK_USERNAME = process.env.BROWSERSTACK_USERNAME;
const BROWSERSTACK_ACCESS_KEY = process.env.BROWSERSTACK_ACCESS_KEY;
const BROWSERSTACK_BUILD_NAME = `Build ${new Date().toISOString()}`;
// Liste des configurations de navigateurs/appareils
const browserConfigs = [
{
browser: 'chrome',
browser_version: 'latest',
os: 'Windows',
os_version: '10',
name: 'Windows Chrome Test'
},
{
browser: 'edge',
browser_version: 'latest',
os: 'Windows',
os_version: '11',
name: 'Windows Edge Test'
},
{
device: 'iPhone 13 Pro',
os_version: '15',
name: 'iOS iPhone Test'
}
];
// Génération du fichier browserstack.json
function generateBrowserStackConfig() {
const config = {
auth: {
username: BROWSERSTACK_USERNAME,
access_key: BROWSERSTACK_ACCESS_KEY
},
browsers: browserConfigs,
run_settings: {
cypress_config_file: './cypress.config.js',
project_name: 'My Project',
build_name: BROWSERSTACK_BUILD_NAME,
callback_url: process.env.CALLBACK_URL || null,
parallels: 1
},
connection_settings: {
local: true,
local_identifier: null
}
};
fs.writeFileSync(
path.join(__dirname, 'browserstack.json'),
JSON.stringify(config, null, 2)
);
console.log('Fichier browserstack.json généré avec succès.');
}
// Téléchargement des rapports de test vers BrowserStack
async function uploadReports() {
const reportDir = path.join(__dirname, 'cypress/reports');
if (!fs.existsSync(reportDir)) {
console.error('Répertoire de rapports non trouvé.');
return;
}
const jsonReports = fs.readdirSync(reportDir)
.filter(file => file.endsWith('.json'));
if (jsonReports.length === 0) {
console.log('Aucun rapport JSON trouvé à télécharger.');
return;
}
for (const report of jsonReports) {
const formData = new FormData();
formData.append('file', fs.createReadStream(path.join(reportDir, report)));
formData.append('build_name', BROWSERSTACK_BUILD_NAME);
try {
const response = await fetch(
`https://api-cloud.browserstack.com/app-automate/cypress/v1/builds/${BROWSERSTACK_BUILD_NAME}/reports`,
{
method: 'POST',
body: formData,
headers: {
'Authorization': 'Basic ' + Buffer.from(`${BROWSERSTACK_USERNAME}:${BROWSERSTACK_ACCESS_KEY}`).toString('base64')
}
}
);
const data = await response.json();
console.log(`Rapport ${report} téléchargé: ${JSON.stringify(data)}`);
} catch (error) {
console.error(`Erreur lors du téléchargement du rapport ${report}:`, error);
}
}
}
// Exécuter les tests sur BrowserStack
async function runOnBrowserStack() {
// Générer la configuration
generateBrowserStackConfig();
// Exécuter la commande de lancement BrowserStack
const { execSync } = require('child_process');
try {
console.log('Démarrage des tests sur BrowserStack...');
execSync('browserstack-cypress run --config-file ./browserstack.json', {
stdio: 'inherit'
});
console.log('Tests terminés sur BrowserStack.');
// Télécharger les rapports
await uploadReports();
} catch (error) {
console.error('Erreur lors de l'exécution des tests sur BrowserStack:', error);
process.exit(1);
}
}
// Exporter les fonctions pour une utilisation dans les scripts npm
module.exports = {
runOnBrowserStack,
generateBrowserStackConfig,
uploadReports
};
// Pour exécuter depuis la ligne de commande:
// node -e "require('./cypress/browserstack').runOnBrowserStack()"
Tests d'applications mobiles avec Appium
Pour les applications mobiles, BrowserStack s'intègre avec Appium :
// tests/mobile/app.test.js
const { remote } = require('webdriverio');
const assert = require('assert');
// Configuration pour les différents appareils à tester
const devices = [
{
name: 'iPhone 13',
platformName: 'iOS',
platformVersion: '15',
deviceName: 'iPhone 13',
app: 'bs://abcdef123456', // ID BrowserStack de l'app iOS
automationName: 'XCUITest'
},
{
name: 'Samsung Galaxy S22',
platformName: 'Android',
platformVersion: '12.0',
deviceName: 'Samsung Galaxy S22',
app: 'bs://654321fedcba', // ID BrowserStack de l'app Android
automationName: 'UIAutomator2'
}
];
// Fonction pour exécuter les tests sur un appareil spécifique
async function runTestOnDevice(deviceConfig) {
// Configuration BrowserStack
const config = {
...deviceConfig,
// Ajout des identifiants BrowserStack
'browserstack.user': process.env.BROWSERSTACK_USERNAME,
'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY,
// Options supplémentaires
'browserstack.debug': true,
'browserstack.networkLogs': true,
'browserstack.geoLocation': 'FR',
// Configuration du test
project: 'Mon Projet Mobile',
build: `Build ${new Date().toISOString()}`,
name: `Test sur ${deviceConfig.name}`
};
// Initialiser le driver WebdriverIO sur BrowserStack
const driver = await remote({
protocol: 'https',
hostname: 'hub-cloud.browserstack.com',
path: '/wd/hub',
port: 443,
capabilities: config,
logLevel: 'error'
});
try {
console.log(`Démarrage du test sur ${deviceConfig.name}`);
// Exemple de test d'une application mobile
// Attendre que l'application démarre
await driver.waitUntil(
async () => {
const element = await driver.$('~login-button');
return element.isExisting();
},
{
timeout: 30000,
timeoutMsg: 'L\'application n\'a pas démarré correctement'
}
);
// Interagir avec les éléments de l'application
// Pour iOS: identifiants accessibles par l'accessibilityId
// Pour Android: identifiants par resource-id ou content-desc
await driver.$('~username-input').setValue('testuser@example.com');
await driver.$('~password-input').setValue('password123');
await driver.$('~login-button').click();
// Attendre que la page principale se charge
await driver.waitUntil(
async () => {
const homeScreen = await driver.$('~home-screen');
return homeScreen.isExisting();
},
{
timeout: 15000,
timeoutMsg: 'La connexion a échoué ou la page principale n\'a pas été chargée'
}
);
// Vérifier que des éléments spécifiques sont présents
const welcomeText = await driver.$('~welcome-message').getText();
assert.ok(welcomeText.includes('Bienvenue'), `Message de bienvenue incorrect: ${welcomeText}`);
// Navigation dans l'application
await driver.$('~menu-button').click();
await driver.$('~settings-option').click();
// Vérifier qu'on a bien accédé aux paramètres
const settingsTitle = await driver.$('~settings-title').getText();
assert.strictEqual(settingsTitle, 'Paramètres', 'Titre de la page des paramètres incorrect');
// Marquer le test comme réussi sur BrowserStack
await driver.executeScript(
'browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"passed","reason": "Tous les tests ont réussi!"}}'
);
console.log(`Test réussi sur ${deviceConfig.name}`);
} catch (error) {
console.error(`Erreur sur ${deviceConfig.name}:`, error);
// Marquer le test comme échoué sur BrowserStack
await driver.executeScript(
`browserstack_executor: {"action": "setSessionStatus", "arguments": {"status":"failed","reason": "${error.message}"}}`
);
throw error;
} finally {
// Fermer le driver
await driver.deleteSession();
}
}
// Exécuter les tests sur tous les appareils configurés
describe('Tests d\'application mobile avec BrowserStack', function() {
// Augmenter le timeout pour les tests sur appareils réels
this.timeout(40 * 60 * 1000); // 40 minutes
for (const device of devices) {
it(`devrait fonctionner sur ${device.name}`, async function() {
await runTestOnDevice(device);
});
}
});
Fonctionnalités principales
- Appareils et navigateurs réels - Tests sur des appareils physiques, pas des émulateurs
- Débogage avancé - Logs, vidéos, captures d'écran et outils de débogage
- Tests parallèles - Exécution simultanée de tests sur plusieurs configurations
- Intégration CI/CD - Compatible avec Jenkins, Travis CI, CircleCI, GitHub Actions, etc.
- Screenshots rapides - Captures d'écran instantanées sur de multiples navigateurs
- Testing responsif - Tests sur différentes tailles d'écran
- Géolocalisation - Tests avec différentes localisations géographiques
- Tests de performance - Mesures de vitesse et analyses avec Lighthouse
Intégration avec les outils de développement
BrowserStack s'intègre avec de nombreux outils et frameworks populaires :
- Frameworks de test -
Selenium,
Cypress, Appium, TestCafe, Playwright, etc.
- Frameworks JavaScript -
Jest, Mocha, Jasmine, etc.
- Systèmes CI/CD - Jenkins, CircleCI,
GitHub Actions, GitLab CI, etc.
- Outils de gestion de test -
Jira, TestRail, etc.
- Frameworks d'automatisation - Protractor, WebdriverIO, NightWatch, etc.
Bonnes pratiques avec BrowserStack
- Optimiser les tests parallèles - Utiliser le maximum de sessions parallèles autorisées par votre plan
- Tester les scénarios critiques - Prioriser les parcours utilisateurs les plus importants
- Utiliser des timeouts appropriés - Prévoir des délais d'attente plus longs que pour les tests locaux
- Marquer le statut des tests - Utiliser l'API browserstack_executor pour indiquer si un test a réussi ou échoué
- Limiter la durée des tests - Garder les tests courts et ciblés
- Utiliser des identifiants de build - Organiser les tests avec des noms de build explicites
- Tirer parti des capacités de débogage - Exploiter les vidéos, captures d'écran et logs
Limites et considérations
- Coût - Service payant avec différents niveaux de tarification basés sur les fonctionnalités et le nombre de sessions parallèles
- Temps d'initialisation - Le démarrage des sessions peut prendre plus de temps que les tests locaux
- Disponibilité des appareils - Les appareils très demandés peuvent parfois être indisponibles
- Temps de session limité - Les sessions ont généralement une durée maximale (entre 30 minutes et 2 heures selon les plans)
- Restrictions réseaux - Certains réseaux d'entreprise peuvent bloquer les connexions nécessaires
BrowserStack est un outil puissant qui simplifie considérablement le test cross-browser et multi-device, permettant aux équipes de développement de se concentrer sur la création de fonctionnalités plutôt que sur la gestion d'une infrastructure de test complexe. En automatisant les tests sur de multiples plateformes, il accélère les cycles de développement tout en garantissant une expérience utilisateur cohérente sur tous les appareils.
Cas d'usage
Tests de compatibilité cross-browser
Vérification qu'un site web ou une application fonctionne correctement sur différentes versions de navigateurs (Chrome, Firefox, Safari, Edge) et systèmes d'exploitation, assurant ainsi une expérience cohérente pour tous les utilisateurs grâce à Selenium.
Test d'applications mobiles
Test d'applications iOS et Android sur des appareils réels de différentes générations, tailles d'écran et versions de système d'exploitation, sans avoir à acquérir et maintenir un large parc d'appareils physiques dans des conteneurs Docker.
Tests de régression automatisés
Exécution automatique de suites de tests avec Jest et
Cypress après chaque modification du code, en parallèle sur plusieurs environnements, pour détecter rapidement les problèmes de compatibilité introduits par les changements.
Test d'applications locales ou internes
Test d'applications en développement ou d'environnements protégés grâce à BrowserStack Local, qui établit un tunnel sécurisé entre l'infrastructure locale et les navigateurs/appareils de BrowserStack avec intégration à GitHub Actions.
Test de design responsif
Vérification du comportement responsive d'un site web sur différentes tailles d'écran et orientations (portrait/paysage), avec possibilité de générer rapidement des captures d'écran sur multiples configurations.
Intégration CI/CD
Intégration des tests BrowserStack dans les pipelines d'intégration et déploiement continus (Jenkins, GitHub Actions, etc.) pour automatiser entièrement le processus de validation cross-browser sur différentes plateformes comme
Docker et bloquer les déploiements en cas de problème.
Intégration dans un workflow de développement
Voici comment BrowserStack s'intègre typiquement dans le flux de travail d'une équipe de développement web :
- Développement local - Les développeurs créent de nouvelles fonctionnalités et les testent d'abord localement sur leur navigateur principal avec
Jest
- Test manuel rapide - Utilisation de BrowserStack Live pour vérifier visuellement le comportement sur d'autres navigateurs/appareils clés
- Création de tests automatisés - Développement de tests
Selenium,
Cypress ou Appium pour les parcours utilisateurs critiques
- Intégration continue - Configuration du pipeline CI avec
GitHub Actions pour exécuter automatiquement les tests sur BrowserStack après chaque commit
- Analyse des résultats - Examen des rapports, captures d'écran et vidéos pour identifier les problèmes
- Débogage des problèmes - Utilisation des outils de débogage BrowserStack pour reproduire et corriger les problèmes spécifiques à certains navigateurs
- Validation avant déploiement - Exécution de tests de régression complets sur l'ensemble des navigateurs et appareils cibles
- Monitoring continu - Tests périodiques automatisés pour détecter les problèmes sur les environnements de production
Cette approche permet de détecter et corriger les problèmes de compatibilité tôt dans le cycle de développement, réduisant considérablement le risque de découvrir des problèmes en production et garantissant une expérience utilisateur cohérente sur toutes les plateformes.