2 週間弱の作業後。ついに Go-DOM の最初の大きなマイルストーンに到達しました。
これで、ブラウザは DOM ツリーを構築するときにリモート JavaScript をダウンロードして実行します。
このプロジェクトは突飛なアイデアとして始まりました。 Go と HTMX がある程度の人気を集めているスタックであることを確認しました。
Go には、純粋なサーバーサイド レンダリングをテストするために必要なツールがすべて含まれています。ただし、HTMX などのライブラリを追加する場合、アプリの動作は最初の DOM 間のコレオグラフィーの結果です。インタラクティブ要素の属性。到達した HTTP エンドポイント、およびそれらのエンドポイントによって配信されたコンテンツ。応答ヘッダーと本文の両方。 ユーザーの視点からの動作を確認するには、ブラウザが必要です。または、少なくとも動作するテスト ハーネス ... ブラウザとまったく異なるわけではありません。1
「go でヘッドレス ブラウザ」を検索すると、本物 ブラウザをヘッドレス モードで使用することを示唆する結果しか得られませんでした。この組み合わせには大きなオーバーヘッドがかかります。高速かつ効率的な TDD ループを阻害します。実際のブラウザに依存すると、通常、速度が上がるではなく、速度が低下します。2
そこでこのアイデアが生まれました。 Web アプリケーションのテスト ツールとして、純粋な Go でヘッドレス ブラウザを作成します。
最初に対処すべき不確実性は、HTML の解析でした。スクリプトの実行も同様です。私はかなり早く成功することができました。これらの両方に対処するには 2 日以内に。私は非常に初歩的な HTML パーサーを持っていました。また、v8 をコード ベース3 に統合し、Go オブジェクトを JavaScript コードからアクセスできるようにしました。
go x/net/html はすでに HTML パーサーを実装しているため、HTML パーサーは後に削除されました。 HTML 解析のあらゆる特殊な問題に対処します。整形式の文書を解析することは、解決するのがそれほど難しい問題ではありません。扱いにくくなる不正な HTML を適切に処理します。
しばらくすると、インライン スクリプトを適切なタイミングで実行できるようになりました。つまり、完全な HTML が解析された後ではなく、要素が実際に DOM に接続されたときにスクリプトが実行されます。
インライン スクリプトで HTML ドキュメントを処理できるようになった後。次のステップは、実際にソースからスクリプトをダウンロードすることでした。これには HTTP 層を統合する必要がありました。ブラウザ自体がコンテンツを取得するようにします。コンテンツを供給されるのではなく。
http.Client では、http.RoundTripper インターフェイスを使用して実際のトランスポート層を制御することもできます。通常はサーバーを起動します。これは、TCP ポートでリクエストをリッスンします。この文脈では、TCP はトランスポート層として機能します。しかし、それ自体は HTTP リクエストの処理には無関係です。 Go の標準 HTTP スタックの単純さのため。 HTTP サーバー全体は、単一関数 func Handle(http.ResponseWriter, *http.Request) によって表されます。
ヘッドレス ブラウザは、TCP スタックのオーバーヘッドを完全にバイパスし、カスタム RoundTripper を使用してこの関数を直接呼び出すことができます。
これでブラウザは HTTP リクエストを実行できるようになりますが、ブラウザ コード自体は HTTP 層がバイパスされていることを認識しません。これにより、DOM 解析中にスクリプトをダウンロードできるようになりました。
コードベースにある簡単なテストを見てみましょう (コードでは、Ginkgo と Gomega が使用されていますが、これは私見ですが、やや見落とされがちな組み合わせです)
まず、テストでは、/index.html と /js/script.js の 2 つのエンドポイントにサービスを提供する単純な HTTP ハンドラーを作成します。
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`)) }, ) // ...
ここでの目的は、スクリプトが実行されることを確認することだけです。これを行うために、スクリプトは、グローバル スコープに値を設定するという目に見える副作用を生成します。
スクリプトが実行されたことを確認するには、グローバル スコープを調べるだけで済みます。これは、テスト自体からアドホック JavaScript を実行することによって行われます。式の結果を検証しています。
ブラウザを作成し、インデックス ファイルをロードし、観察された副作用を検証するコード
browser := ctx.NewBrowserFromHandler(server) Expect(browser.OpenWindow("/index.html")).Error().ToNot(HaveOccurred()) Expect(ctx.RunTestScript("window.scriptLoaded")).To(BeTrue())
テストの実行も非常に高速です。 JavaScript の実行に関係するテスト スイートの部分は現在、23 ミリ秒で実行される 32 のテストで構成されています。
このプロジェクトは当初 HTMX アプリケーションを検証しようとして考案されたものであるため、次の目標はまさにそのケースをサポートすることです。ボタンと、ボタンを押すと増加するカウンターを備えたシンプルな HTMX アプリケーションです。
その後、より高度なユーザー操作が行われます。適切なフォーム処理、例: 入力ハンドライン (例: フィールドで enter を押すとフォームが送信されます。これには通常、ある種の URL リダイレクトも含まれます。これにより履歴オブジェクトなどが必要になります) .
トランスポート層を制御する機能を備えています。独自の機能を備えたテストを提供できます。実行時にシステムが依存する外部サイトをモックアウトできます。たとえば、指定されたホスト名に対して、テストでは動作をシミュレートする別の Go HTTP ハンドラーを提供できます。
最も明白な例は、外部 ID プロバイダーの使用です。このテストでは、ログイン フローの動作をシミュレートできます。外部システムでのダミー アカウントの作成を強制したり、外部システムの停止によりテストが失敗したり、アイデンティティ プロバイダーによって導入された 2FA やキャプチャによりプロセスをまったく自動化できなかったりする必要はありません。
もう 1 つの使用例は、マップ ライブラリなど、使用コストがかかる API を多用するライブラリの使用です。テスト スイートの実行に対して追加の請求を受け取らないように、外部サイトをモックアウトします。
whatwg 標準に 100% 準拠した実装を作成するのは、かなりの努力です。実際に whatwg 仕様の一部を読み始めるまでは、その範囲を完全には理解していませんでした。目標は、Web アプリケーションのテストの作成を支援するツールを作成することです。完全な互換性は長期的な目標です。しかし、プロジェクトがある程度の使いやすさに達するまでは、穴を埋め始めることになるでしょうか。
そのためです。実際のアプリケーションで使用される可能性が高い機能が優先される可能性が高くなります。実際のテストで間違った結果が得られたことを示す機能リクエストが優先される可能性があります。 特定の標準の実装に対する機能リクエストは拒否される可能性があります。
これは多くの開発者にとって非常に役立つツールになると思いますので、これを読んだ場合は、同僚にこのツールの存在を知らせてください。これは今のところ余暇のプロジェクトであり、現時点ではたくさんのプロジェクトがあります。しかし、それは永遠に続くわけではありません。
これを生で見たい場合は、情報を広めてください...
あなたもこれをスポンサーしたいと思いませんか? Go で Web アプリケーションを構築している大企業はありますか?お気軽にご連絡ください。
ここでプロジェクトを見つけてください: https://github.com/stroiman/go-dom
人気の BBC ラジオ劇へのオマージュを聞き取ることができたなら、称賛に値します。 ↩
これは個人的な経験に基づいています。 TDD を正しく行うと、フィードバック サイクルが速くなり、速度が向上します。実際のブラウザのオーバーヘッドにより、製品コードの後にテストを作成する傾向があります。高速テスト スイートが提供するフィードバック ループの利点が失われます。 ↩
v8go プロジェクトによってすでに基礎が築かれていました。しかし; v8 のすべての機能が Go コードに公開されているわけではありません。ネイティブ オブジェクトを埋め込むために必要な機能が含まれています。これらを別のフォークに追加することができました。それはまだ作業中です。 ↩
以上がGo-DOM - 主要なマイルストーンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。