Học Playwright tiếng Việt, Cộng đồng Playwright cho người Việt

Lập trình cơ bản, Lập trình cơ bản, Vọc Vạch Playwright

Tìm hiểu về biến môi trường trong Playwright và Nodejs

Biến môi trường là gì?

Biến môi trường (environment variables) là các giá trị được định nghĩa bên ngoài ứng dụng, có thể truy cập thông qua process.env trong Node.js. Chúng giúp cấu hình ứng dụng mà không cần thay đổi code.

// Truy cập biến môi trường trong Node.js
console.log(process.env.NODE_ENV);    // 'development' hoặc 'production'
console.log(process.env.DATABASE_URL); // 'mongodb://localhost:27017/myapp'
console.log(process.env.API_KEY);      // 'sk-abc123xyz'

Biến môi trường có thể chứa bất kỳ thông tin nào: cấu hình database, API keys, port của server, môi trường chạy (development/production), và nhiều thông tin khác.

Tại sao cần biến môi trường?

1. Bảo mật thông tin nhạy cảm

Thay vì hard-code thông tin nhạy cảm trong code:

// KHÔNG NÊN - Credentials bị lộ trong code
const testUser = {
  username: 'admin@example.com',
  password: 'secretPassword123'
};

Sử dụng biến môi trường:

// NÊN - Thông tin nhạy cảm được giữ bên ngoài code
const testUser = {
  username: process.env.TEST_USERNAME,
  password: process.env.TEST_PASSWORD
};

2. Một code base – Nhiều môi trường

Cùng một code có thể chạy với cấu hình khác nhau cho development, staging, và production:

// playwright.config.js - Tự động adapt theo môi trường
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    headless: process.env.CI === 'true',
    video: process.env.RECORD_VIDEO === 'true' ? 'on' : 'off',
    screenshot: process.env.NODE_ENV === 'development' ? 'only-on-failure' : 'off'
  },
  
  // Development: BASE_URL=http://localhost:3000
  // Staging: BASE_URL=https://staging.myapp.com
  // Production: BASE_URL=https://myapp.com
});

3. Tuân thủ nguyên tắc 12-Factor App

Theo methodology 12-Factor App, cấu hình nên được tách biệt khỏi code. Điều này giúp ứng dụng dễ dàng deploy và scale trên các nền tảng khác nhau (Heroku, AWS, Docker).

4. Dễ dàng thay đổi cấu hình

Không cần sửa code và rebuild khi muốn đổi port, database URL, hay bật/tắt feature:

// test/e2e/login.spec.js
import { test, expect } from '@playwright/test';

test('login flow', async ({ page }) => {
  // Thay đổi URL mà không cần sửa code
  await page.goto(process.env.BASE_URL);
  
  // Bật/tắt feature qua biến môi trường
  if (process.env.ENABLE_2FA === 'true') {
    await page.fill('[data-testid="2fa-code"]', process.env.TEST_2FA_CODE);
  }
  
  // Timeout có thể config từ bên ngoài
  await page.waitForSelector('.dashboard', {
    timeout: parseInt(process.env.TIMEOUT) || 30000
  });
});

Các cách triển khai biến môi trường

Có hai cách chính để set biến môi trường trong Node.js:

  1. Set trực tiếp từ command line – Phù hợp cho các biến tạm thời hoặc scripts
  2. Sử dụng file .env – Phù hợp cho quản lý nhiều biến cấu hình

Set trực tiếp từ command line

Cú pháp cơ bản (khác nhau theo OS)

Trên Mac/Linux:

BROWSER=firefox BASE_URL=https://staging.myapp.com npx playwright test

Trên Windows (Command Prompt):

SET BROWSER=firefox
SET BASE_URL=https://staging.myapp.com
npx playwright test

Trên Windows (PowerShell):

$env:BROWSER="firefox"
$env:BASE_URL="https://staging.myapp.com"
npx playwright test

Vấn đề: Không nhất quán giữa các hệ điều hành

Khi làm việc trong team hoặc deploy lên server, bạn gặp vấn đề:

// package.json
{
  "scripts": {
    // Script này chỉ chạy được trên Mac/Linux
    "test:staging": "BASE_URL=https://staging.myapp.com npx playwright test",
    
    // Developer dùng Windows không chạy được!
    // Họ phải tạo script riêng
    "test:staging-windows": "SET BASE_URL=https://staging.myapp.com && npx playwright test"
  }
}

Điều này dẫn đến:

  • Code không portable (không chạy được mọi nơi)
  • Team phải maintain nhiều scripts
  • CI/CD phức tạp khi server Linux nhưng dev dùng Windows

Giải pháp: Cross-env

Cross-env là package giúp set biến môi trường với cú pháp thống nhất trên mọi hệ điều hành.

Cài đặt:

npm install --save-dev cross-env

Sử dụng trong package.json:

{
  "scripts": {
    // Một script duy nhất - chạy được trên Windows/Mac/Linux
    "test": "cross-env BASE_URL=http://localhost:3000 npx playwright test",
    "test:staging": "cross-env BASE_URL=https://staging.myapp.com HEADLESS=true npx playwright test",
    "test:prod": "cross-env BASE_URL=https://myapp.com HEADLESS=true npx playwright test",
    "test:debug": "cross-env PWDEBUG=1 npx playwright test",
    "test:headed": "cross-env HEADLESS=false SLOW_MO=1000 npx playwright test"
  }
}

Cách cross-env hoạt động:

Khi bạn chạy npm start, cross-env tự động chuyển đổi:

# Bạn viết
cross-env BASE_URL=https://staging.myapp.com npx playwright test

# Cross-env chuyển thành:
# - Trên Windows: SET BASE_URL=https://staging.myapp.com && npx playwright test
# - Trên Mac/Linux: BASE_URL=https://staging.myapp.com npx playwright test

Ví dụ thực tế:

// playwright.config.js
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // Đọc biến từ cross-env
  testDir: './tests',
  timeout: parseInt(process.env.TIMEOUT) || 30000,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  
  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    headless: process.env.HEADLESS !== 'false',
    screenshot: process.env.SCREENSHOT || 'only-on-failure',
    video: process.env.VIDEO || 'retain-on-failure',
    trace: process.env.TRACE || 'on-first-retry',
    
    // Slow motion để debug
    launchOptions: {
      slowMo: process.env.SLOW_MO ? parseInt(process.env.SLOW_MO) : 0
    }
  },
  
  // Browser config từ biến môi trường
  projects: process.env.BROWSER ? [
    { name: process.env.BROWSER, use: { ...devices[process.env.BROWSER] } }
  ] : [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } }
  ]
});

Sử dụng file .env

Khi có nhiều biến môi trường, việc set từ command line trở nên cồng kềnh. File .env giúp quản lý tập trung tất cả biến cấu hình.

Dotenv – Package phổ biến nhất

Cài đặt:

npm install dotenv

Tạo file .env ở root project:

# .env
NODE_ENV=development
BASE_URL=http://localhost:3000

# Test Accounts
TEST_USERNAME=testuser@example.com
TEST_PASSWORD=Test123!@#
ADMIN_USERNAME=admin@example.com
ADMIN_PASSWORD=Admin456$%^

# API Configuration
API_BASE_URL=http://localhost:3001/api
API_KEY=test-api-key-abc123
API_SECRET=test-api-secret-xyz789

# Test Configuration
HEADLESS=false
SLOW_MO=0
TIMEOUT=30000
SCREENSHOT=only-on-failure
VIDEO=off
TRACE=on-first-retry

# Feature Flags
ENABLE_AUTH_TESTS=true
ENABLE_PAYMENT_TESTS=false
SKIP_FLAKY_TESTS=true

Sử dụng trong file config:

// playwright.config.js
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';

// Load biến từ file .env
dotenv.config();

// Hoặc load file .env khác theo môi trường
dotenv.config({ 
  path: `.env.${process.env.NODE_ENV || 'development'}` 
});

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL,
    headless: process.env.HEADLESS === 'true',
    screenshot: process.env.SCREENSHOT,
    video: process.env.VIDEO,
    trace: process.env.TRACE
  },
  
  // Skip flaky tests nếu cần
  grep: process.env.SKIP_FLAKY_TESTS === 'true' ? /@stable/ : undefined,
  grepInvert: process.env.SKIP_FLAKY_TESTS === 'true' ? /@flaky/ : undefined
});

Sử dụng trong test file

// playwright.config.js
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';

// Load biến từ file .env
dotenv.config();

// Hoặc load file .env khác theo môi trường
dotenv.config({ 
  path: `.env.${process.env.NODE_ENV || 'development'}` 
});

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL,
    headless: process.env.HEADLESS === 'true',
    screenshot: process.env.SCREENSHOT,
    video: process.env.VIDEO,
    trace: process.env.TRACE
  },
  
  // Skip flaky tests nếu cần
  grep: process.env.SKIP_FLAKY_TESTS === 'true' ? /@stable/ : undefined,
  grepInvert: process.env.SKIP_FLAKY_TESTS === 'true' ? /@flaky/ : undefined
});

Best practices với dotenv:

  1. Tạo file .env.example:
# .env.example - Commit file này lên git
NODE_ENV=development
BASE_URL=
TEST_USERNAME=
TEST_PASSWORD=
API_KEY=
HEADLESS=true
  1. Thêm .env vào .gitignore:
# .gitignore
.env
.env.local
.env.staging
.env.production
  1. Validate biến môi trường:
// config/validate.js
const required = [
  'BASE_URL',
  'TEST_USERNAME',
  'TEST_PASSWORD'
];

for (const variable of required) {
  if (!process.env[variable]) {
    throw new Error(`Missing required environment variable: ${variable}`);
  }
}
  1. Sử dụng nhiều file .env:
// playwright.config.js
import dotenv from 'dotenv';

// Load file .env theo môi trường
const envFile = process.env.TEST_ENV === 'production' 
  ? '.env.production' 
  : process.env.TEST_ENV === 'staging'
  ? '.env.staging'
  : '.env.development';

dotenv.config({ path: envFile });

console.log(`Loaded config from ${envFile}`);
console.log(`Testing against: ${process.env.BASE_URL}`);

Dotenvx – Phiên bản nâng cao

Dotenvx là version mới với nhiều tính năng bổ sung, đặc biệt là mã hóa file .env.

Cài đặt:

npm install @dotenvx/dotenvx

Tính năng nổi bật:

  1. Mã hóa file .env:
# Mã hóa file .env thành .env.vault
npx dotenvx encrypt

# Chạy tests với file đã mã hóa
DOTENV_KEY=your_key npx dotenvx run -- npx playwright test
  1. Hỗ trợ nhiều môi trường:
# Tạo các file .env cho từng môi trường
.env.development   # Local testing
.env.staging      # Staging tests
.env.production   # Production smoke tests

# Tự động load đúng file
npx dotenvx run --env-file=.env.staging -- npx playwright test
  1. Validate và type safety:
// config/env.schema.js
const schema = {
  BASE_URL: { type: 'string', required: true, pattern: '^https?://' },
  TEST_USERNAME: { type: 'string', required: true, pattern: '^.+@.+$' },
  TIMEOUT: { type: 'number', default: 30000 },
  HEADLESS: { type: 'boolean', default: true }
};

Kết hợp cross-env và dotenv

Trong thực tế, hai công cụ này thường được dùng cùng nhau:

// package.json
{
  "scripts": {
    // cross-env override biến cụ thể, dotenv load các biến mặc định
    "test": "npx playwright test",
    "test:chrome": "cross-env BROWSER=chromium npx playwright test",
    "test:firefox": "cross-env BROWSER=firefox npx playwright test",
    "test:headed": "cross-env HEADLESS=false npx playwright test",
    "test:staging": "cross-env TEST_ENV=staging npx playwright test",
    "test:ci": "cross-env CI=true HEADLESS=true npx playwright test"
  }
}
// playwright.config.js
import { defineConfig } from '@playwright/test';
import dotenv from 'dotenv';

// Load dotenv dựa trên TEST_ENV từ cross-env
const envFile = `.env.${process.env.TEST_ENV || 'development'}`;
dotenv.config({ path: envFile });

console.log('Environment:', process.env.TEST_ENV || 'development');
console.log('Testing URL:', process.env.BASE_URL);
console.log('Headless:', process.env.HEADLESS !== 'false');

export default defineConfig({
  use: {
    baseURL: process.env.BASE_URL,
    headless: process.env.HEADLESS !== 'false'
  }
});

Best Practices tổng hợp

  1. Không bao giờ commit file .env chứa thông tin nhạy cảm
  2. Luôn có file .env.example để hướng dẫn team
  3. Validate biến môi trường khi khởi động app
  4. Dùng cross-env cho npm scripts để đảm bảo cross-platform
  5. Tổ chức biến môi trường theo nhóm trong file .env
  6. Sử dụng naming convention nhất quán (UPPER_SNAKE_CASE)
  7. Document rõ ràng ý nghĩa của từng biến
  8. Tạo helper functions để đọc và parse biến môi trường
// helpers/env.js
export const getConfig = () => ({
  baseURL: process.env.BASE_URL || 'http://localhost:3000',
  credentials: {
    username: process.env.TEST_USERNAME,
    password: process.env.TEST_PASSWORD
  },
  timeout: parseInt(process.env.TIMEOUT) || 30000,
  isCI: process.env.CI === 'true',
  isHeadless: process.env.HEADLESS !== 'false'
});

Biến môi trường là công cụ không thể thiếu trong automation testing với Playwright, giúp test suite linh hoạt, bảo mật và dễ maintain trên nhiều môi trường khác nhau.

Trả lời