Go-DOM – wichtiger Meilenstein

Mary-Kate Olsen
Freigeben: 2024-11-22 02:44:17
Original
169 Leute haben es durchsucht

Go-DOM -  major milestone

Nach knapp 2 Wochen Arbeit; Endlich habe ich den ersten großen Meilenstein für Go-DOM erreicht.

Jetzt lädt der Browser beim Erstellen des DOM-Baums Remote-JavaScript herunter und führt es aus.

Eine kurze Geschichte

Das Projekt begann als verrückte Idee; Angesichts der Tatsache, dass Go und HTMX ein Stack sind, der immer beliebter wird;

Go verfügt bereits über alle Tools, die Sie zum Testen des rein serverseitigen Renderings benötigen. Beim Hinzufügen einer Bibliothek wie HTMX ist das Verhalten der App jedoch das Ergebnis einer Choreografie zwischen dem anfänglichen DOM; die Attribute interaktiver Elemente; die erreichten HTTP-Endpunkte und die von diesen Endpunkten bereitgestellten Inhalte; sowohl Antwortheader als auch -text. Um das Verhalten aus Benutzersicht zu verifizieren, benötigen Sie einen Browser; oder zumindest ein Testgerät, das sich verhält ... einem Browser nicht ganz unähnlich.1

Die Suche nach „Headless Browser in Go“ führte nur zu Ergebnissen, die darauf hindeuteten, einen echten Browser im Headless-Modus zu verwenden. Diese Kombination hat einen enormen Overhead; Entmutigung der schnellen und effizienten TDD-Schleife. Wenn Sie sich auf einen echten Browser verlassen, werden Sie in der Regel verlangsamt statt beschleunigt.2

So entstand die Idee; Schreiben Sie einen Headless-Browser in Pure Go als Testtool für Webanwendungen;

Die ersten zu behebenden Unsicherheiten betrafen das Parsen von HTML; sowie Skriptausführung. Ich habe es ziemlich schnell geschafft; innerhalb von 2 Tagen, um beide Probleme zu beheben. Ich hatte einen sehr rudimentären HTML-Parser; Außerdem hatte ich v8 in die Codebasis integriert3 und Go-Objekte für JavaScript-Code zugänglich gemacht.

Der HTML-Parser wurde später entfernt, da go x/net/html bereits einen HTML-Parser implementiert; Umgang mit allen Macken des HTML-Parsings. Das Parsen eines wohlgeformten Dokuments ist kein besonders schwierig zu lösendes Problem. Es geht elegant mit fehlerhaftem HTML um, wo es schwierig wird.

Nach einiger Zeit gelang es mir auch, die Inline-Skriptausführung im richtigen Moment auszuführen; Das heißt, das Skript wird ausgeführt, wenn das Element tatsächlich mit dem DOM verbunden ist, nicht nachdem der vollständige HTML-Code analysiert wurde.

Arbeiten mit HTTP-Anfragen

Nachdem Sie ein HTML-Dokument mit Inline-Skript verarbeiten konnten; Der nächste Schritt bestand darin, tatsächlich Skripte von der Quelle herunterzuladen. Dies erforderte die Integration einer HTTP-Schicht; so dass der Browser Inhalte selbst abruft; anstatt mit Inhalten gefüttert zu werden.

Mit dem http.Client können Sie auch die eigentliche Transportschicht über die http.RoundTripper-Schnittstelle steuern. Normalerweise starten Sie einen Server. die auf Anfragen an einem TCP-Port lauscht. In diesem Zusammenhang dient TCP als Transportschicht; ist aber für die Verarbeitung von HTTP-Anfragen selbst irrelevant. Aufgrund der Einfachheit des Standard-HTTP-Stacks in Go; Ein gesamter HTTP-Server wird durch eine einzige Funktion dargestellt, func Handle(http.ResponseWriter, *http.Request).

Der Headless-Browser kann den Overhead des TCP-Stacks vollständig umgehen und diese Funktion direkt mit einem benutzerdefinierten RoundTripper aufrufen.

Jetzt kann der Browser HTTP-Anfragen ausführen, aber der Browsercode selbst weiß nicht, dass die HTTP-Schicht umgangen wird. Und damit verbunden war die Möglichkeit, das Skript während der DOM-Analyse herunterzuladen.

Beispielcode

Lassen Sie uns einen einfachen Test untersuchen, wie er jetzt in der Codebasis aussieht (der Code verwendet Ginkgo und Gomega, meiner Meinung nach eine etwas übersehene Kombination)

Zuerst erstellt der Test einen einfachen HTTP-Handler, der zwei Endpunkte bedient, /index.html und /js/script.js.

It("Should download and execute script from script tags", func() {
  // Setup a server with test content
  server := http.NewServeMux()
  server.HandleFunc(
    "GET /index.html",
    func(res http.ResponseWriter, req *http.Request) {
      res.Write(
        []byte(
          `<html><head><script src="/js/script.js"></script></head><body>Hello, World!</body>`,
        ),
      )
    },
  )
  server.HandleFunc(
    "GET /js/script.js",
    func(res http.ResponseWriter, req *http.Request) {
      res.Header().Add("Content-Type", "text/javascript")
      res.Write([]byte(`var scriptLoaded = true`))
    },
  )

  // ...
Nach dem Login kopieren

Die Absicht hier ist lediglich, zu überprüfen, dass das Skript ausgeführt wird. Zu diesem Zweck erzeugt das Skript einen beobachtbaren Nebeneffekt: Es legt einen Wert im globalen Bereich fest.

Um zu überprüfen, ob das Skript ausgeführt wurde, muss lediglich der globale Geltungsbereich untersucht werden. Dies geschieht durch die Ausführung von Ad-hoc-JavaScript aus dem Test selbst heraus. Überprüfung des Ergebnisses des Ausdrucks.

Der Code zum Erstellen des Browsers, Laden der Indexdatei und Überprüfen des beobachteten Nebeneffekts

browser := ctx.NewBrowserFromHandler(server)
Expect(browser.OpenWindow("/index.html")).Error().ToNot(HaveOccurred())
Expect(ctx.RunTestScript("window.scriptLoaded")).To(BeTrue())
Nach dem Login kopieren

Testausführung ist auch ziemlich schnell. Der Teil der Testsuite, der die Ausführung von JavaScript beinhaltet, besteht derzeit aus 32 Tests, die in 23 Millisekunden ausgeführt werden.

Nächster Meilenstein: Integration von HTMX.

Da das Projekt ursprünglich bei dem Versuch konzipiert wurde, eine HTMX-Anwendung zu verifizieren, besteht ein vernünftiges nächstes Ziel darin, genau diesen Fall zu unterstützen. Eine einfache HTMX-Anwendung mit einer Schaltfläche und einem Zähler, der sich erhöht, wenn die Schaltfläche gedrückt wird.

  • EineXMLHttpRequest-Implementierung muss vorhanden sein. Daran wird gearbeitet.
  • Ein XPathEvaluator. Ich glaube, dass es von Anfang an polygefüllt sein kann.
  • Ereignisweitergabe. Derzeit werden nur DOMContentLoaded- und Load-Ereignisse ausgegeben. Elemente müssen mehr Ereignisse unterstützen; wie zum Beispiel klicken; sowie Methoden, um sie auszulösen.
    • Dies erfordert möglicherweise auch eine ordnungsgemäße Ereigniserfassung und Bubbling.

Und dann ...

Anschließend erweiterte Benutzerinteraktion; ordnungsgemäße Handhabung des Formulars, z. B. Eingabehandline (z. B. durch Drücken der Eingabetaste in einem -Feld wird das Formular gesendet. Dies beinhaltet normalerweise auch eine Art URL-Umleitung, die die Notwendigkeit eines Verlaufsobjekts usw. erhöht .

Integration externer Seiten

Mit der Fähigkeit, die Transportschicht zu steuern; Wir können Tests mit einzigartigen Fähigkeiten anbieten; Wir können externe Websites nachahmen, von denen das System zur Laufzeit abhängig wäre. Beispielsweise könnte der Test für einen bestimmten Hostnamen einen anderen Go-HTTP-Handler bereitstellen, der das Verhalten simuliert.

Das offensichtlichste Beispiel ist die Verwendung externer Identitätsanbieter. Der Test könnte das Verhalten eines Anmeldeflusses simulieren; Sie müssen nicht gezwungen werden, Dummy-Konten in einem externen System zu erstellen, Testfehler aufgrund von Ausfällen in einem externen System zu erleiden oder den Prozess aufgrund von 2FA oder einem vom Identitätsanbieter eingeführten Captcha einfach überhaupt nicht automatisieren zu können.

Ein weiterer Anwendungsfall ist die Verwendung von API-intensiven Bibliotheken, wie z. B. Kartenbibliotheken, für die Nutzungskosten anfallen. Verspotten Sie die externe Website, um keine zusätzliche Rechnung für den Betrieb Ihrer Testsuite zu erhalten.

Benutzerfreundlichkeit geht vor Kompatibilität

Eine zu 100 % mit den Whatwg-Standards konforme Implementierung zu erstellen, ist ein ziemliches Unterfangen; Ich verstand den Umfang erst vollständig, als ich tatsächlich anfing, Teile der whatwg-Spezifikationen zu lesen. Ziel ist es, ein Tool zu erstellen, das das Schreiben von Tests für Webanwendungen unterstützt. Volle Kompatibilität ist ein langfristiges Ziel; Aber bis das Projekt ein gewisses Maß an Benutzerfreundlichkeit erreicht hat, werde ich damit beginnen, die Lücken zu füllen.

Aus diesem Grund; Funktionen, die mit größerer Wahrscheinlichkeit in tatsächlichen Anwendungen verwendet werden, werden mit größerer Wahrscheinlichkeit priorisiert. Eine Funktionsanfrage, die auf einen tatsächlichen Test verweist, der ein falsches Ergebnis liefert, wird wahrscheinlich priorisiert. Eine Funktionsanfrage zur Implementierung eines bestimmten Standards wird wahrscheinlich abgelehnt.

Verbreiten Sie es weiter

Ich glaube, dass dies für viele Entwickler ein sehr nützliches Tool sein kann. Wenn Sie dies also lesen, teilen Sie Ihren Kollegen mit, dass es existiert. Dies ist bisher ein Freizeitprojekt, von dem ich im Moment reichlich habe; aber das wird nicht ewig so bleiben.

Wenn Sie das live sehen möchten, sagen Sie es weiter ...

Vielleicht würden Sie das sogar sponsieren? Haben Sie ein großes Unternehmen, das Webanwendungen in Go erstellt? Kontaktieren Sie mich gerne.

Das Projekt finden Sie hier: https://github.com/stroiman/go-dom


  1. Ein großes Lob, wenn Sie es geschafft haben, die Hommage an ein beliebtes BBC-Hörspiel zu sehen. ↩

  2. Dies basiert auf persönlichen Erfahrungen. Wenn Sie TDD richtig ausführen, werden Sie aufgrund des schnellen Feedback-Zyklus schneller. Der Overhead eines echten Browsers führt dazu, dass Sie Tests nach dem Produktionscode schreiben müssen. Sie verlieren den Nutzen der Feedbackschleife, die Ihnen eine schnelle Testsuite bietet. ↩

  3. Der Grundstein wurde bereits durch das v8go-Projekt gelegt. Jedoch; Nicht alle Funktionen von Version 8 sind für Go-Code verfügbar. einschließlich notwendiger Funktionen zum Einbetten nativer Objekte. Ich konnte diese in einem separaten Fork hinzufügen; Das ist noch in Bearbeitung. ↩

Das obige ist der detaillierte Inhalt vonGo-DOM – wichtiger Meilenstein. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage