--- title: Pruebas description: Configuración de Vitest, pruebas de integración contra un servidor real de Twenty, comprobación de tipos e integración continua (CI) con GitHub Actions. icon: flask --- El SDK proporciona APIs programáticas que te permiten compilar, desplegar, instalar y desinstalar tu aplicación desde código de pruebas. Combinado con [Vitest](https://vitest.dev/) y los clientes de API tipados, puedes escribir pruebas de integración que verifiquen que tu aplicación funciona de extremo a extremo contra un servidor real de Twenty. ## Uso de paquetes de npm Puedes instalar y usar cualquier paquete de npm en tu aplicación. Tanto las funciones de lógica como los componentes de frontend se empaquetan con [esbuild](https://esbuild.github.io/), que incorpora todas las dependencias en la salida — no se necesitan `node_modules` en tiempo de ejecución. ### Instalar un paquete ```bash filename="Terminal" yarn add axios ``` Luego impórtalo en tu código: ```ts src/logic-functions/fetch-data.ts import { defineLogicFunction } from 'twenty-sdk/define'; import axios from 'axios'; const handler = async (): Promise => { const { data } = await axios.get('https://api.example.com/data'); return { data }; }; export default defineLogicFunction({ universalIdentifier: '...', name: 'fetch-data', description: 'Fetches data from an external API', timeoutSeconds: 10, handler, }); ``` Lo mismo funciona para los componentes de frontend: ```tsx src/front-components/chart.tsx import { defineFrontComponent } from 'twenty-sdk/define'; import { format } from 'date-fns'; const DateWidget = () => { return

Today is {format(new Date(), 'MMMM do, yyyy')}

; }; export default defineFrontComponent({ universalIdentifier: '...', name: 'date-widget', component: DateWidget, }); ``` ### Cómo funciona el empaquetado El paso de compilación usa esbuild para producir un solo archivo autónomo por función de lógica y por componente de frontend. Todos los paquetes importados se insertan en el bundle. **Las funciones de lógica** se ejecutan en un entorno Node.js. Los módulos integrados de Node (`fs`, `path`, `crypto`, `http`, etc.) están disponibles y no necesitan instalarse. **Los componentes de frontend** se ejecutan en un Web Worker. Los módulos integrados de Node **no** están disponibles — solo las APIs del navegador y paquetes de npm que funcionen en un entorno de navegador. Ambos entornos tienen `twenty-client-sdk/core` y `twenty-client-sdk/metadata` disponibles como módulos preproporcionados — estos no se incluyen en el bundle sino que se resuelven en tiempo de ejecución por el servidor. ## Configuración La aplicación generada ya incluye Vitest. Si lo configuras manualmente, instala las dependencias: ```bash filename="Terminal" yarn add -D vitest vite-tsconfig-paths ``` Crea un `vitest.config.ts` en la raíz de tu aplicación: ```ts vitest.config.ts import tsconfigPaths from 'vite-tsconfig-paths'; import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [ tsconfigPaths({ projects: ['tsconfig.spec.json'], ignoreConfigErrors: true, }), ], test: { testTimeout: 120_000, hookTimeout: 120_000, include: ['src/**/*.integration-test.ts'], setupFiles: ['src/__tests__/setup-test.ts'], env: { TWENTY_API_URL: 'http://localhost:2020', TWENTY_API_KEY: 'your-api-key', }, }, }); ``` Crea un archivo de configuración que verifique que el servidor es accesible antes de ejecutar las pruebas: ```ts src/__tests__/setup-test.ts import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { beforeAll } from 'vitest'; const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020'; const TEST_CONFIG_DIR = path.join(os.tmpdir(), '.twenty-sdk-test'); beforeAll(async () => { // Verify the server is running const response = await fetch(`${TWENTY_API_URL}/healthz`); if (!response.ok) { throw new Error( `Twenty server is not reachable at ${TWENTY_API_URL}. ` + 'Start the server before running integration tests.', ); } // Write a temporary config for the SDK fs.mkdirSync(TEST_CONFIG_DIR, { recursive: true }); fs.writeFileSync( path.join(TEST_CONFIG_DIR, 'config.json'), JSON.stringify({ remotes: { local: { apiUrl: process.env.TWENTY_API_URL, apiKey: process.env.TWENTY_API_KEY, }, }, defaultRemote: 'local', }, null, 2), ); }); ``` ## APIs programáticas del SDK La subruta `twenty-sdk/cli` exporta funciones que puedes invocar directamente desde el código de pruebas: | Función | Descripción | | -------------- | ------------------------------------------------------------ | | `appBuild` | Compilar la aplicación y opcionalmente empaquetar un tarball | | `appDeploy` | Subir un tarball al servidor | | `appInstall` | Instalar la aplicación en el espacio de trabajo activo | | `appUninstall` | Desinstalar la aplicación del espacio de trabajo activo | Cada función devuelve un objeto de resultado con `success: boolean` y `data` o `error`. ## Escribir una prueba de integración Aquí tienes un ejemplo completo que compila, despliega e instala la aplicación, y luego verifica que aparezca en el espacio de trabajo: ```ts src/__tests__/app-install.integration-test.ts import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application-config'; import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli'; import { MetadataApiClient } from 'twenty-client-sdk/metadata'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; const APP_PATH = process.cwd(); describe('App installation', () => { beforeAll(async () => { const buildResult = await appBuild({ appPath: APP_PATH, tarball: true, onProgress: (message: string) => console.log(`[build] ${message}`), }); if (!buildResult.success) { throw new Error(`Build failed: ${buildResult.error?.message}`); } const deployResult = await appDeploy({ tarballPath: buildResult.data.tarballPath!, onProgress: (message: string) => console.log(`[deploy] ${message}`), }); if (!deployResult.success) { throw new Error(`Deploy failed: ${deployResult.error?.message}`); } const installResult = await appInstall({ appPath: APP_PATH }); if (!installResult.success) { throw new Error(`Install failed: ${installResult.error?.message}`); } }); afterAll(async () => { await appUninstall({ appPath: APP_PATH }); }); it('should find the installed app in the workspace', async () => { const metadataClient = new MetadataApiClient(); const result = await metadataClient.query({ findManyApplications: { id: true, name: true, universalIdentifier: true, }, }); const installedApp = result.findManyApplications.find( (app: { universalIdentifier: string }) => app.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER, ); expect(installedApp).toBeDefined(); }); }); ``` ## Ejecutar pruebas Asegúrate de que tu servidor local de Twenty esté en ejecución y luego: ```bash filename="Terminal" yarn test ``` O en modo watch durante el desarrollo: ```bash filename="Terminal" yarn test:watch ``` ## Comprobación de tipos También puedes ejecutar la comprobación de tipos en tu aplicación sin ejecutar pruebas: ```bash filename="Terminal" yarn twenty dev:typecheck ``` Esto ejecuta `tsc --noEmit` e informa cualquier error de tipo. ## CI con GitHub Actions El generador crea un flujo de trabajo de GitHub Actions listo para usar en `.github/workflows/ci.yml`. Ejecuta tus pruebas de integración automáticamente en cada push a `main` y en los pull requests. El flujo de trabajo: 1. Obtiene tu código 2. Inicia un servidor temporal de Twenty usando la acción `twentyhq/twenty/.github/actions/spawn-twenty-docker-image` 3. Instala las dependencias con `yarn install --immutable` 4. Ejecuta `yarn test` con `TWENTY_API_URL` y `TWENTY_API_KEY` inyectados a partir de las salidas de la acción ```yaml .github/workflows/ci.yml name: CI on: push: branches: - main pull_request: {} env: TWENTY_VERSION: latest jobs: test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Spawn Twenty instance id: twenty uses: twentyhq/twenty/.github/actions/spawn-twenty-docker-image@main with: twenty-version: ${{ env.TWENTY_VERSION }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: Enable Corepack run: corepack enable - name: Setup Node.js uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' cache: 'yarn' - name: Install dependencies run: yarn install --immutable - name: Run integration tests run: yarn test env: TWENTY_API_URL: ${{ steps.twenty.outputs.server-url }} TWENTY_API_KEY: ${{ steps.twenty.outputs.access-token }} ``` No necesitas configurar secretos: la acción `spawn-twenty-docker-image` inicia un servidor efímero de Twenty directamente en el runner y devuelve los detalles de conexión. El secreto `GITHUB_TOKEN` lo proporciona GitHub automáticamente. Para fijar una versión específica de Twenty en lugar de `latest`, cambia la variable de entorno `TWENTY_VERSION` al inicio del flujo de trabajo.