Aller au contenu principal

Tester et débugger

Tester votre app avant la publication

Une application bien testée est une application qui passe la review du Store et qui satisfait ses utilisateurs. Le Apps SDK fournit des outils de test et de débogage intégrés que vous devez maîtriser.

Le Playground de développement

Le playground est votre premier outil de test. Il simule l’environnement ChatGPT en local.

# Lancer le playground
npx chatgpt-app dev

# Options disponibles
npx chatgpt-app dev --port 3200       # Port personnalisé
npx chatgpt-app dev --verbose          # Logs détaillés
npx chatgpt-app dev --mock-auth        # Simuler l'authentification

Le playground affiche :

  • Une interface de conversation simulée
  • Un panneau de logs en temps réel
  • Un inspecteur de widgets
  • Un moniteur de requêtes réseau

Tests unitaires des actions

Testez vos actions indépendamment avec le test runner du SDK :

// tests/actions/weather.test.ts
import { testAction } from "@openai/apps-sdk/testing";
import { getWeather } from "../src/actions/weather";

describe("getWeather", () => {
  it("retourne la météo pour une ville valide", async () => {
    const result = await testAction(getWeather, {
      params: { city: "Paris" },
      mockContext: { user: { id: "test-user" } },
    });

    expect(result.city).toBe("Paris");
    expect(result.temperature).toBeDefined();
    expect(typeof result.temperature).toBe("number");
  });

  it("gère les villes inconnues", async () => {
    await expect(
      testAction(getWeather, {
        params: { city: "VilleInexistante123" },
      })
    ).rejects.toThrow("NOT_FOUND");
  });

  it("respecte le rate limiting", async () => {
    // Appeler 21 fois (limite = 20/min)
    for (let i = 0; i < 20; i++) {
      await testAction(getWeather, { params: { city: "Lyon" } });
    }

    await expect(
      testAction(getWeather, { params: { city: "Lyon" } })
    ).rejects.toThrow("RATE_LIMITED");
  });
});

Tests de widgets

Vérifiez que vos widgets produisent le rendu attendu :

// tests/widgets/weather-card.test.ts
import { testWidget } from "@openai/apps-sdk/testing";
import { weatherCard } from "../src/widgets/weather-card";

describe("weatherCard", () => {
  it("affiche correctement les données météo", () => {
    const rendered = testWidget(weatherCard, {
      city: "Paris",
      temperature: 22,
      windSpeed: 15,
      condition: "Ciel dégagé",
      timestamp: "2026-04-01T10:00:00Z",
    });

    expect(rendered.type).toBe("card");
    expect(rendered.title).toContain("Paris");

    // Vérifier les métriques
    const metrics = rendered.content.find((c) => c.type === "grid");
    expect(metrics.items).toHaveLength(2);
    expect(metrics.items[0].value).toBe("22°C");
  });

  it("gère les données manquantes", () => {
    const rendered = testWidget(weatherCard, {
      city: "Lyon",
      temperature: null,
    });

    // Le widget ne doit pas crasher
    expect(rendered.type).toBe("card");
  });
});

Tests d’intégration (flows)

Testez le parcours complet action → widget :

// tests/flows/weather-flow.test.ts
import { testFlow } from "@openai/apps-sdk/testing";
import { app } from "../src/index";

describe("Weather Flow", () => {
  it("affiche la météo après recherche", async () => {
    const result = await testFlow(app, {
      userMessage: "Quelle est la météo à Marseille ?",
      expectedAction: "getWeather",
      expectedWidget: "weatherCard",
    });

    expect(result.actionCalled).toBe(true);
    expect(result.widgetRendered).toBe(true);
    expect(result.widgetData.city).toBe("Marseille");
  });
});

Débogage en temps réel

Logs structurés

Le SDK fournit un logger intégré :

import { logger } from "@openai/apps-sdk";

handler: async ({ city }, context) => {
  logger.info("Recherche météo", { city, userId: context.user.id });

  try {
    const data = await fetchWeather(city);
    logger.debug("Données reçues", { temperature: data.temp });
    return data;
  } catch (error) {
    logger.error("Erreur API météo", { city, error: error.message });
    throw new ActionError("INTERNAL", "Service météo indisponible");
  }
}

Inspecteur de requêtes

Le playground inclut un inspecteur réseau qui affiche :

  • Chaque requête HTTP sortante (URL, headers, body)
  • Le temps de réponse
  • Le code de statut
  • Le body de la réponse

Mode debug avancé

# Activer les logs détaillés
CHATGPT_APP_DEBUG=true npx chatgpt-app dev

# Logs de chaque décision du modèle
CHATGPT_APP_DEBUG=model npx chatgpt-app dev

# Logs des échanges réseau
CHATGPT_APP_DEBUG=network npx chatgpt-app dev

Erreurs courantes et solutions

Erreur Cause probable Solution
ACTION_NOT_FOUND Action non enregistrée Vérifier app.action() dans index.ts
WIDGET_RENDER_ERROR Données invalides pour le widget Valider les données avant le render
AUTH_TOKEN_EXPIRED Token OAuth expiré Implémenter le refresh token
TIMEOUT Action trop lente (> 30s) Optimiser ou découper l'action

Checklist avant soumission

Avant de soumettre votre app au Store, vérifiez :

  • Toutes les actions retournent des données valides pour le cas nominal
  • Les erreurs sont gérées avec des ActionError explicites
  • Les widgets ne crashent pas avec des données partielles ou nulles
  • L’authentification fonctionne de bout en bout
  • Le rate limiting est configuré sur les actions sensibles
  • Les tests passent à 100 %

Points clés à retenir

  • Le playground simule ChatGPT en local pour tester sans publier
  • Testez actions, widgets et flows séparément avec les helpers du SDK
  • Utilisez le logger structuré pour un débogage efficace
  • Les erreurs courantes ont des solutions connues — consultez la table de référence
  • Passez la checklist de pré-soumission avant de publier sur le Store