TypeScript + Playwright/Puppeteer测试标签通信

huangapple go评论134阅读模式
英文:

TypeScript + Playwright/Puppeteer Test Tab communication

问题

以下是您提供的文本的中文翻译:

我尝试使用 Playwright 来测试我的演示 broadcastChannel 模块,但我无法将 Class 传递给 evaluate,或者将类实例注入到 Window。以下是最小可复现的示例。

utils.ts

  1. export class Utils {
  2. public static formatTime() { return new Date().toLocaleString(); }
  3. public static generateRandomStr() { /* 生成随机字符串的逻辑 */ }
  4. }

index.ts

  1. import { Utils } from "./utils";
  2. export class Channel<T extends string> {
  3. private uniqueID = Utils.generateRandomStr();
  4. private channel: BroadcastChannel;
  5. constructor(name: T) {
  6. this.channel = new BroadcastChannel(name);
  7. this.onMessage();
  8. }
  9. private onMessage() {
  10. this.channel.addEventListener("message", e => {
  11. console.log(e.data);
  12. });
  13. }
  14. public sendMsg(msg: any) {
  15. this.channel.postMessage({
  16. id: this.uniqueID,
  17. time: Utils.formatTime(),
  18. msg,
  19. });
  20. }
  21. public sendHelloWorld() {
  22. this.sendMsg("Hello World");
  23. }
  24. public sendByeWorld() {
  25. this.sendMsg("Bye World");
  26. }
  27. }

根据 @Sheldon Oliveira 的回答和 这个 Stack Overflow 回答,我了解到没有简单的方法来将 Class 或类实例传递给 evaluate。也许我选择了错误的方法来测试标签间通信,我希望有更好的解决方案。

以下是我尝试的两种不同方法。

  1. import { test, expect, Page } from '@playwright/test';
  2. import { Channel } from '../src/index';
  3. let page1: Page, page2: Page;
  4. test.beforeEach(async ({ context }) => {
  5. [page1, page2] = await Promise.all([context.newPage(), context.newPage()]);
  6. await Promise.all([page1.goto("https://www.google.com"), page2.goto("https://www.google.com")]);
  7. });
  8. test.afterEach(async ({ context }) => {
  9. await Promise.all([page1.close(), page2.close()]);
  10. await context.close();
  11. });
  12. test('sendHelloWorld', async () => {
  13. await Promise.all([
  14. await page1.evaluate((strClass) => {
  15. eval("window.Channel = " + strClass);
  16. window.channel = new window.Channel();
  17. // ^ReferenceError: _Utils is not defined
  18. }, Channel.toString()),
  19. await page2.evaluate((strClass) => {
  20. eval("window.Channel = " + strClass);
  21. window.channel = new window.Channel();
  22. // ^ReferenceError: _Utils is not defined
  23. }, Channel.toString()),
  24. ]);
  25. const msgPromise = page2.waitForEvent("console");
  26. await page1.evaluate(() => {
  27. window.channel.sendHelloWorld();
  28. });
  29. const msg = await msgPromise;
  30. expect((await msg.args()[0].jsonValue()).msg).toBe("Hello World");
  31. });
  32. test('sendByeWorld', async () => {
  33. await Promise.all([
  34. await page1.evaluate((channel) => {
  35. window.channel = channel;
  36. // ^ no prototype method sendByeWorld
  37. }, new Channel()),
  38. await page2.evaluate((channel) => {
  39. window.channel = channel;
  40. // ^ no prototype method sendByeWorld
  41. }, new Channel()),
  42. ]);
  43. const msgPromise = page2.waitForEvent("console");
  44. await page1.evaluate(() => {
  45. window.channel.sendHelloWorld();
  46. });
  47. const msg = await msgPromise;
  48. expect((await msg.args()[0].jsonValue()).msg).toBe("Bye World");
  49. });

期望的控制台技巧来自于 Playwright 文档

我还添加了 "puppeteer" 标签,因为我认为无论使用哪个框架,问题都是相同的。

英文:

I tried to test my demo broadcastChannel module with playwright. But I cannot pass Class to evaluate or inject class instance to Window. Below is the minimal reproducible example.

utils.ts

  1. export class Utils {
  2. public static formatTime() { return new Date().toLocaleString(); }
  3. public static generateRandomStr() { /* generate random str logic*/ }
  4. }

index.ts

  1. import { Utils } from &quot;./utils&quot;;
  2. export class Channel&lt;T extends string&gt; {
  3. private uniqueID = Utils.generateRandomStr();
  4. private channel: BroadcastChannel;
  5. constructor(name: T) {
  6. this.channel = new BroadcastChannel(name);
  7. this.onMessage();
  8. }
  9. private onMessage() {
  10. this.channel.addEventListener(&quot;message&quot;, e =&gt; {
  11. console.log(e.data);
  12. });
  13. }
  14. public sendMsg(msg: any) {
  15. this.channel.postMessage({
  16. id: this.uniqueID,
  17. time: Utils.formatTime(),
  18. msg,
  19. });
  20. }
  21. public sendHelloWorld() {
  22. this.sendMsg(&quot;Hello World&quot;);
  23. }
  24. public sendByeWorld() {
  25. this.sendMsg(&quot;Bye World&quot;);
  26. }
  27. }

According to @Sheldon Oliveira's answer and this stackoverflow answer, I got that there's no easy way to pass Class or class instance to evaluate. Maybe I went for the wrong way to test tab communication, I hope there's a better solution.

Below are the two different approches I tried.

  1. import { test, expect, Page } from &#39;@playwright/test&#39;;
  2. import { Channel } from &#39;../src/index&#39;;
  3. let page1: Page, page2: Page;
  4. test.beforeEach(async ({ context }) =&gt; {
  5. [page1, page2] = await Promise.all([context.newPage(), context.newPage()]);
  6. await Promise.all([page1.goto(&quot;https://www.google.com&quot;), page2.goto(&quot;https://www.google.com&quot;)]);
  7. });
  8. test.afterEach(async ({ context }) =&gt; {
  9. await Promise.all([page1.close(), page2.close()]);
  10. await context.close();
  11. });
  12. test(&#39;sendHelloWorld&#39;, async () =&gt; {
  13. await Promise.all([
  14. await page1.evaluate((strClass) =&gt; {
  15. eval(&quot;window.Channel = &quot; + strClass);
  16. window.channel = new window.Channel();
  17. // ^ReferenceError: _Utils is not defined
  18. }, Channel.toString()),
  19. await page2.evaluate((strClass) =&gt; {
  20. eval(&quot;window.Channel = &quot; + strClass);
  21. window.channel = new window.Channel();
  22. // ^ReferenceError: _Utils is not defined
  23. }, Channel.toString()),
  24. ]);
  25. const msgPromise = page2.waitForEvent(&quot;console&quot;);
  26. await page1.evaluate(() =&gt; {
  27. window.channel.sendHelloWorld();
  28. });
  29. const msg = await msgPromise;
  30. expect((await msg.args()[0].jsonValue()).msg).toBe(&quot;Hello World&quot;);
  31. });
  32. test(&#39;sendByeWorld&#39;, async () =&gt; {
  33. await Promise.all([
  34. await page1.evaluate((channel) =&gt; {
  35. window.channel = channel;
  36. // ^ no prototype method sendByeWorld
  37. }, new Channel()),
  38. await page2.evaluate((channel) =&gt; {
  39. window.channel = channel;
  40. // ^ no prototype method sendByeWorld
  41. }, new Channel()),
  42. ]);
  43. const msgPromise = page2.waitForEvent(&quot;console&quot;);
  44. await page1.evaluate(() =&gt; {
  45. window.channel.sendHelloWorld();
  46. });
  47. const msg = await msgPromise;
  48. expect((await msg.args()[0].jsonValue()).msg).toBe(&quot;Bye World&quot;);
  49. });

The expect console trick is from playwright documentation.

I also added puppeteer tag, cause I think the problem is the same regardless of the framework.

答案1

得分: 1

TLDR; 你不能将类作为评估的参数使用。

文档:
此参数可以是可序列化的值和JSHandle或ElementHandle实例的混合。

一个类不是可序列化的值。

英文:

TLDR; you can not use a class as a parameter for evaluate.

docs:
This argument can be a mix of Serializable values and JSHandle or ElementHandle instances.

A class is not a serializable value.

huangapple
  • 本文由 发表于 2023年6月6日 00:53:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76408515.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定