Arbeitsplatz Bild SEQIS Group GmbH

Atlassian Forge Custom UI Testing und Asynchronität

Description

Daniel Kleißl von SEQIS spricht in seinem devjobs.at TechTalk über eine Eigenheit von Forge beim UI Testing und zeigt in einer Live Demo, wie das Team dieses Problem gelöst hat.

Beim Videoaufruf stimmst Du der Datenübermittlung an YouTube und der Datenschutzerklärung zu.

Video Zusammenfassung

In „Atlassian Forge Custom UI Testing und Asynchronität“ zeigt Daniel Kleißl (SEQIS Group GmbH), warum Forge-Custom-UI in einer Atlassian-Sandbox läuft und der Import der Forge-Bridge im normalen Browser scheitert, was eine lokale Ausführung ohne Umwege verhindert. Er demonstriert eine praxistaugliche Teststrategie: die Forge-Bridge per Mock/Stub in einer vorangestellten Datei bereitstellen, mit der React Testing Library rendern und Bridge-Responses wie ein API mocken. Im zweiten Teil erklärt er, wie Mocha asynchrone Fehler verschluckt und wie Nodes unhandled-rejections im Strict-Modus aussagekräftige Stacktraces liefert—konkrete Tipps, um Tests für Forge-Apps stabil und aussagekräftig zu machen.

Atlassian Forge Custom UI Testing und Asynchronität: Bridge-Mocks, React-Tests und Node-Flags – was wir aus Daniel Kleißls Talk gelernt haben

Kontext: Ein präziser Deep-Dive statt Framework-Marketing

In „Atlassian Forge Custom UI Testing und Asynchronität“ zeigte Daniel Kleißl (SEQIS Group GmbH) eine selten geradlinige Perspektive auf ein sehr spezielles, dafür umso relevanteres Problem: Wie testet man Atlassian-Forge-Apps mit Custom UI sauber – insbesondere wenn die Browser-Umgebung nicht dem Standard entspricht und asynchrone Fehler im Test-Runner „versickern“?

Als Redaktion von DevJobs.at haben wir den Talk verfolgt und die zentralen technischen Erkenntnisse herausgearbeitet. Der Fokus lag ausdrücklich auf Praxis: Kleißl skizzierte, wie seine Einheit bei ratzfatz.eu (dem Development Department von SEQIS) ihre Forge-App „Intelligent Risk Assessment – Journey to Rome“ zur Marktreife bringt – und welche Stolpersteine im Testing dabei ganz real auftreten. Seine Leitidee: „Viele Wege führen nach Rom – aber vielleicht ist Rom nicht das Ziel.“ Übertragen auf Frameworks bedeutet das: Der vorgegebene Pfad funktioniert, solange man genau dorthin will. Wer ein anderes Ziel hat (andere Toolchains, andere Qualitätsansprüche, andere Teststrategie), muss umdenken – oder tricksen.

Wer spricht – und warum es relevant ist

Daniel Kleißl ist seit rund zwei Jahren bei SEQIS und als Lead Developer für die Atlassian-Forge-App „Intelligent Risk Assessment – Journey to Rome“ verantwortlich. Parallel absolviert er sein Bachelorstudium an der FH Campus Wien (zum Zeitpunkt des Talks war der Abschluss unmittelbar bevorstehend). Dieser Kontext ist für das Thema Testing nicht nur ein persönlicher Hintergrund: Er zeichnet das Bild eines Teams, das eine produktionsreife Forge-App in den Marketplace bringt und daher Testing-Fragen nicht theoretisch, sondern mit Produktionsdruck klärt.

Forge in Kürze: Was die Plattform kann – und wo die Tücken beginnen

Atlassian nennt Forge eine „Serverless App Development Plattform“ für Atlassian Cloud Produkte – konkret Confluence Cloud, Jira Cloud und Jira Service Management Cloud. Der Charme: Hosting, Laufzeit und Integration kommen von Atlassian; Third-Party-Entwickler können relativ schnell Apps entwickeln und im Atlassian Marketplace bereitstellen.

Kleißl betont, dass man auf React-Basis zügig produktive Tools bauen kann – ob für Kunden oder die eigene Organisation. In der Praxis entsteht dann rasch der Wunsch, diese Apps nicht nur zu deployen, sondern robust zu testen. Und genau hier setzt sein Talk an.

Die Forge-Architektur: Runtime, UI Kit, Custom UI – und die Bridge

Wesentlich für das Verständnis der Testproblematik ist die Architektur. Kleißl unterscheidet:

  • Runtime: Der Teil, in dem Atlassian die Ausführung managt.
  • UI Kit: Für einfachere UI-Anforderungen gedacht.
  • Custom UI: Für vollwertige React-Apps, die in einer Sandbox laufen.

Damit eine Custom-UI-React-App mit der Forge-Runtime und der Atlassian-Instanz kommunizieren kann, existiert die Forge Bridge. Sie vermittelt zwischen der sandboxed React-App und dem produktseitigen Kontext. Das ist elegant – bis man testen will, ohne dass die Atlassian-Umgebung tatsächlich da ist. Genau dann entpuppt sich die Bridge als Engstelle.

Das Kernproblem: Non-Standard-Browser-Environment

Kleißl zeigt es mit einer simplen Live-Demo: Eine minimalistische React-App rendert zunächst korrekt – ein Div mit Box und Bild. Sobald jedoch der Import der Forge Bridge aktiviert wird, ist im lokalen Browser Schluss. In der Konsole erscheint der bekannte, aber in diesem Fall besonders aufschlussreiche Fehler:

Unable to establish a connection with the custom UI bridge, if you are trying to run your app locally, Forge apps only work in the context of Atlassian products.

Was passiert? Die Bridge möchte „nach Hause telefonieren“ – zum Atlassian-Kontext – und scheitert, weil der lokale Browser diese Umgebung nicht bereitstellt. Ergebnis: Kein Rendern, kein UI, keine Basis für UI-Tests.

Konsequenz für Tests: Ohne Bridge-Mock geht nichts

Wenn bereits der Import der Bridge eine echte Instanz erwartet, müssen wir im Testkontext nachhelfen. Kleißls Vorgehen:

  • React Testing Library nutzen, um Komponenten zu rendern und Assertions auf UI-Zustände zu formulieren.
  • Ein Mocking-Framework einsetzen, um die Forge Bridge zu ersetzen.
  • Einen Stub/Mok der Forge Bridge in einer Datei definieren, die vor allen anderen Imports geladen wird, die die Bridge referenzieren.

Die Reihenfolge ist hier entscheidend: Der Bridge-Stub muss vor jedem anderen Code importiert werden, der sich auf die Bridge bezieht. So „täuschen“ die Tests der App eine funktionierende Bridge vor. Anschließend behandelt man die Bridge-Aufrufe wie ein normales API: Responses mocken, erwartete Werte definieren, UI-Verhalten asserten. Welche Endpunkte die Bridge bereitstellt, ist in der Forge-Dokumentation beschrieben – das ist für die Tests die maßgebliche Referenz.

Wichtig: Sobald der Stub an der richtigen Stelle sitzt, verhält sich die Testumgebung aus Sicht der React-Komponenten wie ein übliches Setup. Rendering, Events, State-Transitions – alles kann wie gewohnt verifiziert werden.

Demos, die den Unterschied machen: Vom „leeren Bildschirm“ zum verlässlichen Test

Kleißl führt durch die Abfolge:

  1. Eine minimale React-Komponente rendert lokal korrekt.
  2. Allein der Import der Forge Bridge führt im lokalen Browser zur Fehlermeldung und verhindert das Rendering.
  3. Erst ein früher, zentraler Bridge-Stub schafft die Voraussetzung, dass Komponenten im Testlauf überhaupt initialisieren und reagieren.

Diese Einfachheit ist trügerisch, denn sie unterstreicht: Ohne das gezielte Mocking der Bridge ist jeder weitere Testschritt Makulatur. Es geht nicht um komplexe Testlogik – es geht um das Fundament, auf dem Tests überhaupt lauffähig sind.

Asynchronität unter der Lupe: Wenn Mocha Fehler „verschluckt“

Mit aktivem Bridge-Mock sind die UI-Tests möglich – aber eine zweite Klasse von Problemen bleibt: Asynchrone Fehler, die im Test-Runner nicht klar sichtbar werden.

Kleißl beschreibt das Verhalten in Mocha so: Asynchrone Errors werden „verschluckt“. Das ist kein Bug, sondern „Works As Designed“. Hintergrund ist, dass „Uncaught Promise Rejections“ nicht mehr als Exception geworfen werden. Stattdessen erscheinen sie als Warnung oder gehen im Runner-Verhalten unter.

Warum ist das kritisch? Weil es die Fehlersuche verlängert. Kleißl will nicht nur „Happy Paths“ testen, sondern bewusst Edge Cases und banale Programmierfehler abdecken – etwa Tippfehler, falsch referenzierte Funktionen oder Rejections aus asynchronen Calls. Wenn der ursprüngliche Fehler nicht sauber ausgewiesen wird, wird das Debugging zum Ratespiel.

Eine prototypische UI-Situation

Kleißl skizziert einen sehr typischen Ablauf:

  • Eine UI enthält einen Button.
  • Der Button löst einen Event-Handler aus.
  • Der Handler ruft eine asynchrone Funktion auf.
  • Nach erfolgreichem Abschluss wird ein Loading-Flag auf false gesetzt, woraufhin ein zuvor verstecktes Div sichtbar wird.

Der Testfall klickt den Button per React Testing Library, dann „wartet“ er per Timeout darauf, dass das Div angezeigt wird – das ist der Assert. Was aber, wenn die asynchrone Funktion einen Fehler wirft (oder sogar ein banaler Tippfehler vorliegt)?

Ohne besondere Maßnahmen meldet Mocha lediglich, dass das erwartete Div nicht erschienen ist. Der eigentliche Grund – etwa eine unhandled Promise Rejection – ist im Stacktrace nicht sichtbar. Für die Ursache-Diagnose ist das unzureichend.

Das gewünschte Verhalten: Ein klarer Stacktrace

Kleißl will in solchen Fällen explizit sehen, was schiefging. Etwa eine Meldung vom Typ „Unhandled Promise Rejection“ – mit Stacktrace, der auf den eigentlichen Auslöser verweist. Nur so lässt sich schnell klären, ob der Fehler im Testsetup, im Mock, in der Komponente oder in der asynchronen Business-Logik liegt.

Die pragmatische Lösung: Node-Flag für „Strict Mode“ bei unhandled rejections

Nach Recherche in Foren und Q&A-Plattformen stieß Kleißl (eigene Worte) über ein Gespräch mit einem LLM auf die passende Lösung: Ein Node-Flag, das unhandled Promise Rejections wieder strikt behandelt. Mit diesem „Unhandled Rejections Strict“-Modus zeigt der Testlauf wieder Stacktraces für asynchrone Fehler – exakt das gewünschte Signal.

Der Effekt ist in seinen Demos klar sichtbar: Startet er denselben Testlauf mit dem zusätzlichen Flag, erscheint im Output der Stacktrace. Statt eines „Timeout beim Warten auf ein Div“ erhält man quellnahe Hinweise – inklusive „Unhandled Promise Rejection“. Für die schnelle Ursachenanalyse ist dieser Unterschied erheblich.

Bemerkenswert an dieser Episode ist weniger die Herkunft der Lösung als der Ansatz: Kleißl kommentiert offen, dass es manchmal genau diese kleine Systemoption ist, die das Testen von „zäh“ auf „zielgerichtet“ umstellt.

„Rom vs. Konstantinopel“: Warum Framework-Vorgaben nicht immer dein Ziel sind

Die Metapher, die Kleißl mehrfach betont, wirkt hier besonders schlüssig: Ein Framework ist oft so gebaut, dass man in „Rom“ landet – sprich: im vorgesehenen Standardpfad. Wer eine andere Teststrategie verfolgt, muss Wege finden, anderswo anzukommen. Beim Custom-UI-Testing in Forge bedeutet das konkret:

  • Der Standardbrowser ist nicht die Forge-Umgebung – also muss die Bridge im Test speziell behandelt werden.
  • Der Standardmodus von Mocha ist nicht auf strikte Fehlerpropagierung ausgelegt – also muss die Node-Laufzeit entsprechend konfiguriert werden.

Beide Schritte sind keine großen Umbauten – aber sie sind zwingend, wenn man Testing als Qualitätswerkzeug versteht und nicht nur als „Smoke Check“.

Schritt-für-Schritt-Orientierung: So setzt ihr Kleißls Ansatz um

Im Talk arbeitet Kleißl mit konkreten Demos. Aus redaktioneller Sicht lassen sich seine Empfehlungen in folgende Handlungssequenz übertragen:

  1. Verständnis der Forge-Architektur festigen.
  • Wisst, dass Custom UI in einer Sandbox läuft und über eine Bridge mit der Forge-Runtime spricht.
  • Erwartet nicht, dass euer Lokalbrowser die Forge-Bridge von sich aus bereitstellt.
  1. Testgrundlage mit React Testing Library schaffen.
  • Nutzt die bekannten Render- und Querying-Patterns.
  • Definiert Assertions auf das, was nach User-Events sichtbar sein soll.
  1. Forge Bridge konsequent mocken.
  • Erstellt einen Bridge-Stub in einer separaten Datei.
  • Importiert diese Datei vor allen anderen Modulen, die die Bridge importieren oder referenzieren.
  • Behandelt Bridge-Aufrufe wie ein typisches API; mockt die erwarteten Responses zielgerichtet pro Test.
  1. Asynchrone Fehler sichtbar machen.
  • Akzeptiert, dass Mocha unhandled Rejections standardmäßig nicht als Exception wirft.
  • Aktiviert den strikten Umgang mit unhandled Rejections in der Node-Laufzeit, damit Stacktraces wieder im Testoutput erscheinen.
  1. Edge Cases bewusst abdecken.
  • Simuliert Rejections aus asynchronen Funktionen.
  • Testet auch banale Programmierfehler (z. B. Tippfehler, falsch gesetzte Imports), um euer Setup zu validieren.
  1. Dokumentation gezielt nutzen.
  • Nutzt die Forge-Dokumentation, um die verfügbaren Bridge-Endpunkte gezielt zu mocken.

Typische Testmuster, die sich aus dem Talk ableiten

Kleißls Beispiele sind bewusst minimal. Daraus lassen sich robuste Testmuster ableiten:

  • „Button klickt Async-Handler“: Prüft das gesamte Ereignis vom Event bis zur UI-Reaktion – inklusive des Falls, dass die asynchrone Funktion fehlschlägt.
  • „Conditional Rendering nach Laden“: Nutzt die Wartefunktionen der Testing Library, um UI-Zustände nach asynchronen Operationen zu überprüfen.
  • „Verdeckte Fehler sichtbar machen“: Erzwingt die Sichtbarkeit von unhandled Rejections, um Debugging-Zeit zu sparen.

Diese Muster sind keineswegs forge-spezifisch – aber in Forge-Umgebungen sind sie wegen der Bridge-Situation unverhandelbar.

Grenzen und Klarstellungen aus dem Talk

Kleißl blieb bei seinen Aussagen nah an der Praxis und vermied Verallgemeinerungen. Aus unserer Sicht sind drei Klarstellungen zentral:

  • Die gezeigte Mocha-Konfiguration ist „Works As Designed“ – kein Bug, sondern eine bewusste Laufzeitentscheidung. Wer strengere Fehlerpropagierung wünscht, muss das Node-Verhalten anpassen.
  • Der Bridge-Stub ist nicht optional. Sobald die Forge Bridge importiert wird, erwartet sie die Atlassian-Umgebung. Tests ohne Stub laufen lokal nicht an.
  • Welche Bridge-Endpunkte verfügbar sind, bestimmt die Forge-Dokumentation. Testmocks sollten sich daran orientieren – nicht umgekehrt.

Wirkung in der Praxis: Warum sich der Aufwand lohnt

Wer UI-Tests als Integrationswerkzeug begreift, profitiert hier in mehrfacher Hinsicht:

  • Schnellere Ursachenanalyse: Statt nebulöser Timeouts liefert der Testlauf stacktrace-basierte Hinweise.
  • Stabilere Pipelines: Tests, die auch unglückliche Edge Cases abdecken, verhindern Regressionen, wenn die App wächst.
  • Bessere Entwicklererfahrung: Einmal korrekt aufgesetzt, fühlt sich das Testen wie gewohntes React-Testing an – trotz Spezialumgebung.

Ausblick und Ressourcen, die Kleißl nennt

Kleißl verweist auf die Forge-Dokumentation als Startpunkt. Darüber hinaus hat er einen separaten „10-More-Things“-Talk gehalten, in dem er das Framework „von Anfang bis Ende bis zum Release im Marketplace“ durchdekliniert – ein Versprechen auf Tiefe, nicht auf Marketing. Seine eigene App („Intelligent Risk Assessment – Journey to Rome“) ist im Atlassian Marketplace kostenlos installierbar – ein lohnender Blick, wenn man sehen will, was mit Forge im realen Einsatz möglich ist.

Fazit: Kleine Hebel, große Wirkung – wenn man die Architektur ernst nimmt

„Atlassian Forge Custom UI Testing und Asynchronität“ von Daniel Kleißl (SEQIS Group GmbH) ist ein Plädoyer für präzises, pragmatisches Engineering. Zwei Maßnahmen entscheiden, ob eure Tests tragfähig sind:

  • Mockt die Forge Bridge früh und eindeutig, damit die Custom UI in Tests überhaupt lauffähig ist.
  • Erzwingt die strikte Behandlung von unhandled Promise Rejections, damit asynchrone Fehler sichtbar – und schnell behebbar – werden.

Beides sind keine „Tricks“, sondern Anerkennung der Rahmenbedingungen, unter denen Forge-Apps entstehen. Wenn „Rom“ nicht euer Ziel ist, braucht ihr einen Plan für „Konstantinopel“. Kleißls Ansatz zeigt: Der Weg ist klar – und gar nicht so weit, wenn man weiß, wo die entscheidenden Schalter sitzen.

Weitere Tech Talks

Weitere Tech Lead Stories

Weitere Dev Stories