Go-DOM - 重大里程碑
工作了不到两周;我终于达到了 Go-DOM 的第一个重要里程碑。
现在,浏览器将在构建 DOM 树时下载并执行远程 JavaScript
。简史
这个项目最初是一个疯狂的想法;看到 Go 和 HTMX 是一个越来越受欢迎的堆栈;
Go 已经拥有测试纯服务器端渲染所需的所有工具。但是,当添加像 HTMX 这样的库时,应用程序的行为是初始 DOM 之间编排的结果;交互元素的属性;到达的 HTTP 端点以及这些端点传送的内容;响应标头和正文。要从用户的角度验证行为,您需要一个浏览器;或者至少是一个行为...与浏览器并不完全不同的测试工具。1
搜索“Go 中的无头浏览器”只会导致建议在无头模式下使用真实浏览器的结果。这种组合有巨大的开销;阻碍快速高效的 TDD 循环。依赖真实的浏览器通常会减慢您的速度而不是加快您的速度。2
于是这个想法就被激发了;用纯 Go 编写一个无头浏览器作为 Web 应用程序的测试工具;
首先要解决的不确定性是 HTML 的解析;以及脚本执行。我很快就做到了; 2天内解决这两个问题。我有一个非常基本的 HTML 解析器;我还将 v8 集成到代码库中3
并使 Go 对象可以被 JavaScript 代码访问。HTML 解析器后来被删除,因为 go x/net/html 已经实现了 HTML 解析器;处理 HTML 解析的所有怪癖。解析格式良好的文档并不是一个非常难解决的问题。它可以优雅地处理格式错误的 HTML,但在这方面却变得棘手。
过了一段时间,我还设法让内联
脚本执行在正确的时刻运行;即当元素实际连接到 DOM 时执行脚本,而不是在解析完整的 HTML 之后执行。处理 HTTP 请求
能够使用内联脚本处理 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,恕我直言,这是一个有点被忽视的组合)
首先,测试创建一个简单的 HTTP 处理程序,该处理程序提供两个端点:/index.html 和 /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`)) }, ) // ...
此处的目的只是验证脚本是否已执行。为此,脚本会产生一个可观察到的副作用:它在全局范围内设置一个值。
要验证脚本是否已执行,只需检查全局范围,这是通过从测试本身执行临时 JavaScript 来完成的;验证表达式的结果。
创建浏览器、加载索引文件并验证观察到的副作用的代码
browser := ctx.NewBrowserFromHandler(server) Expect(browser.OpenWindow("/index.html")).Error().ToNot(HaveOccurred()) Expect(ctx.RunTestScript("window.scriptLoaded")).To(BeTrue())
测试执行也相当快。测试套件中涉及 JavaScript 执行的部分目前由 32 个测试组成,运行时间为 23 毫秒。
下一个里程碑是集成 HTMX。
由于该项目最初是在尝试验证 HTMX 应用程序时构思的,因此合理的下一个目标是支持这种情况。一个简单的 HTMX 应用程序,带有一个按钮和一个计数器,按下按钮时计数器会增加。
- AnXMLHttpRequest 实现需要就位。为此,工作正在进行中。
- XPathEvaluator。我相信一开始就可以填充。
- 事件传播。现在仅发出 DOMContentLoaded 和 load 事件。元素需要支持更多的事件;比如点击;以及触发它们的方法。
- 这可能还需要正确的事件捕获和冒泡。
进而 ...
接下来是更高级的用户交互;正确的表单处理,例如,输入手线(例如,在 字段中按 enter 提交表单。这通常还涉及某种 URL 重定向;这驱动了对历史对象等的需求.
集成外部站点
具有控制传输层的能力;我们可以提供具有独特能力的测试;我们可以模拟系统在运行时依赖的外部站点。例如,对于给定的主机名,测试可以提供另一个模拟行为的 Go HTTP 处理程序。
最明显的例子是使用外部身份提供商。该测试可以模拟登录流程的行为;不必强迫您在外部系统中创建虚拟帐户,由于外部系统中断而导致测试失败,或者由于身份提供商引入的 2FA 或验证码而根本无法自动化该过程。
另一个用例是使用 API 密集型库,例如地图库,这会产生使用成本。模拟外部站点,以免因运行测试套件而收到额外费用。
可用性胜于兼容性
创建 100% 符合 Whatwg 标准的实现是一项艰巨的任务;直到我真正开始阅读 Whatwg 规范的部分内容之前,我并没有完全理解其范围。目标是创建一个工具帮助为 Web 应用程序编写测试。完全兼容是一个长期目标;但在项目达到某种程度的可用性之前,我会开始填补漏洞。
因此;在实际应用中更可能使用的功能更有可能被优先考虑。指向给出错误结果的实际测试的功能请求可能会被优先考虑。 实施特定标准的功能请求可能会被拒绝。
传播这个词
我相信这对于许多开发人员来说都是一个非常有用的工具,所以如果您阅读了本文,请让您的同事知道它的存在。到目前为止,这只是一个业余时间项目,目前我有很多空闲时间;但情况不会永远如此。
如果你想现场观看,请传播出去......
也许您甚至会赞助这个?您有一家使用 Go 构建 Web 应用程序的大公司吗?欢迎联系我。
在这里找到项目:https://github.com/stroiman/go-dom
-
如果您成功地听到了对 BBC 流行广播剧的致敬,那就太好了。 ↩
-
这是基于个人经验。由于快速的反馈周期,正确执行 TDD 会加快你的速度。真实浏览器的开销往往会让您在生产代码之后编写测试;失去了快速测试套件为您提供的反馈循环的好处。 ↩
-
v8go 项目已经奠定了基础。然而;并非 v8 的所有功能都暴露给 Go 代码;包括嵌入本机对象的必要功能。我能够将它们添加到单独的叉子中;这仍然是 WIP。 ↩
以上是Go-DOM - 重大里程碑的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

OpenSSL,作为广泛应用于安全通信的开源库,提供了加密算法、密钥和证书管理等功能。然而,其历史版本中存在一些已知安全漏洞,其中一些危害极大。本文将重点介绍Debian系统中OpenSSL的常见漏洞及应对措施。DebianOpenSSL已知漏洞:OpenSSL曾出现过多个严重漏洞,例如:心脏出血漏洞(CVE-2014-0160):该漏洞影响OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻击者可利用此漏洞未经授权读取服务器上的敏感信息,包括加密密钥等。

后端学习路径:从前端转型到后端的探索之旅作为一名从前端开发转型的后端初学者,你已经有了nodejs的基础,...

Go语言中用于浮点数运算的库介绍在Go语言(也称为Golang)中,进行浮点数的加减乘除运算时,如何确保精度是�...

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

在BeegoORM框架下,如何指定模型关联的数据库?许多Beego项目需要同时操作多个数据库。当使用Beego...

Go语言中字符串打印的区别:使用Println与string()函数的效果差异在Go...

Go语言中使用RedisStream实现消息队列时类型转换问题在使用Go语言与Redis...

GoLand中自定义结构体标签不显示怎么办?在使用GoLand进行Go语言开发时,很多开发者会遇到自定义结构体标签在�...
