globalSetup corre una vez antes de que cualquier worker del navegador arranque, en el proceso principal, lo que significa que no puedes pasar objetos JavaScript a los tests: comparte datos a través de archivos escritos en disco o variables de entorno configuradas con process.env. El uso más común es iniciar sesión una vez y guardar el resultado con storageState, para que cada test de la suite empiece autenticado sin repetir el flujo de login. Esta guía cubre el patrón de estado de auth, múltiples roles de usuario con archivos de almacenamiento separados, seeding de base de datos, teardown global, y el patrón de setup condicional que omite el re-login cuando ya existe un archivo de auth reciente.

Qué es el global setup

Playwright ejecuta una función globalSetup una vez antes de que empiece toda la suite de tests, y una función globalTeardown una vez después de que todo termina. Estas corren en el proceso principal, antes de que arranquen los workers del navegador.

Usa global setup para:

  • Autenticarte y guardar storageState (el uso más común)
  • Sembrar la base de datos de test con datos base
  • Iniciar un servidor mock o de test
  • Generar archivos de datos de test

Configuración básica

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

export default defineConfig({
  globalSetup: require.resolve('./global-setup'),
  globalTeardown: require.resolve('./global-teardown'),
  use: {
    baseURL: 'http://localhost:3000',
  },
});

El uso más común: guardar el estado de auth

// global-setup.ts
import { chromium, FullConfig } from '@playwright/test';

async function globalSetup(config: FullConfig) {
  const { baseURL } = config.projects[0].use;
  const browser = await chromium.launch();
  const page = await browser.newPage();

  await page.goto(`${baseURL}/login`);
  await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!);
  await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!);
  await page.getByRole('button', { name: 'Iniciar sesión' }).click();
  await page.waitForURL(`${baseURL}/dashboard`);

  // Guardar cookies + localStorage para reutilizar
  await page.context().storageState({ path: 'playwright/.auth/user.json' });
  await browser.close();
}

export default globalSetup;

// playwright.config.ts: usar el auth guardado en todos los tests
use: {
  storageState: 'playwright/.auth/user.json',
},

Cada test ahora empieza ya autenticado. Sin paso de login. Sin configuración de sesión por test. El login ocurre una sola vez.

Múltiples roles de usuario

Para aplicaciones con roles de administrador y usuario regular:

// global-setup.ts
async function globalSetup(config: FullConfig) {
  const { baseURL } = config.projects[0].use;
  const browser = await chromium.launch();

  // Guardar auth de admin
  const adminPage = await browser.newPage();
  await loginAs(adminPage, `${baseURL}`, process.env.ADMIN_EMAIL!, process.env.ADMIN_PASSWORD!);
  await adminPage.context().storageState({ path: 'playwright/.auth/admin.json' });
  await adminPage.close();

  // Guardar auth de usuario regular
  const userPage = await browser.newPage();
  await loginAs(userPage, `${baseURL}`, process.env.USER_EMAIL!, process.env.USER_PASSWORD!);
  await userPage.context().storageState({ path: 'playwright/.auth/user.json' });
  await userPage.close();

  await browser.close();
}

async function loginAs(page: Page, baseURL: string, email: string, password: string) {
  await page.goto(`${baseURL}/login`);
  await page.getByLabel('Email').fill(email);
  await page.getByLabel('Password').fill(password);
  await page.getByRole('button', { name: 'Iniciar sesión' }).click();
  await page.waitForURL(`${baseURL}/dashboard`);
}

Luego usa diferentes estados de auth por proyecto:

// playwright.config.ts
projects: [
  {
    name: 'admin-tests',
    use: { storageState: 'playwright/.auth/admin.json' },
    testMatch: '**/admin/**/*.spec.ts',
  },
  {
    name: 'user-tests',
    use: { storageState: 'playwright/.auth/user.json' },
    testMatch: '**/user/**/*.spec.ts',
  },
],

Seeding de base de datos en global setup

// global-setup.ts
import { Pool } from 'pg';

async function globalSetup() {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });

  // Sembrar datos base una sola vez
  await pool.query(`
    INSERT INTO users (email, password_hash, role)
    VALUES ('testusuario@ejemplo.com', $1, 'user')
    ON CONFLICT (email) DO NOTHING
  `, [hashedPassword]);

  await pool.end();
}

El seeding de base de datos en global setup funciona para datos base estáticos. Para datos específicos de un test que necesitan aislarse y limpiarse, usa fixtures en su lugar: corren por test y se limpian solos.

Global teardown

// global-teardown.ts
import { Pool } from 'pg';

async function globalTeardown() {
  // Limpiar datos de test después de toda la suite
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  await pool.query("DELETE FROM users WHERE email LIKE '%@test.ejemplo.com'");
  await pool.end();

  // Detener cualquier servidor iniciado en globalSetup
  // (si guardaste una referencia en process o global)
}

export default globalTeardown;

Compartir datos entre global setup y los tests

Global setup corre en un proceso separado al de los tests. No puedes pasar objetos JavaScript directamente. Las opciones son:

Archivos

Guarda datos en disco en global setup, léelos en los tests.

// global-setup.ts
import fs from 'fs';

async function globalSetup() {
  const testData = { userId: '123', orderId: '456' };
  fs.writeFileSync('playwright/.test-data.json', JSON.stringify(testData));
}

// en los tests
import testData from '../playwright/.test-data.json';
test('usa datos sembrados', async ({ page }) => {
  await page.goto(`/orders/${testData.orderId}`);
});

Variables de entorno

Configúralas en global setup con process.env.KEY = value. Están disponibles en los procesos worker de tests. Úsalas para valores simples (IDs, tokens).

Ejecutar global setup condicionalmente

Omitir global setup cuando corrés tests individuales en local:

// global-setup.ts
async function globalSetup() {
  // Saltear si el archivo de auth ya existe y es reciente
  const authFile = 'playwright/.auth/user.json';
  if (fs.existsSync(authFile)) {
    const stats = fs.statSync(authFile);
    const ageMinutes = (Date.now() - stats.mtimeMs) / 60000;
    if (ageMinutes < 30) {
      console.log('El estado de auth es reciente, omitiendo login...');
      return;
    }
  }

  // De lo contrario, iniciar sesión y guardar
  // ...
}

Esto hace que las ejecuciones locales repetidas sean más rápidas: el paso de login solo ocurre cuando el auth guardado no existe o está desactualizado.

→ See also: Manejo de Autenticación en Playwright con storageState (Sin Iniciar Sesión en Cada Test) | Fixtures de Playwright Explicados: De los Integrados a los Personalizados | Aislamiento de Tests: Por qué Cada Test de Playwright Debe ser sin Estado