Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: support for strict CSP broken by style mutation #816

Open
razor-x opened this issue Jan 27, 2022 · 31 comments
Open

Regression: support for strict CSP broken by style mutation #816

razor-x opened this issue Jan 27, 2022 · 31 comments

Comments

@razor-x
Copy link

razor-x commented Jan 27, 2022

The optimization in PR #464 broke support for users who run a strict Content-Security-Policy (CSP).

Specifically, this line sets the style attribute on a DOM node and will be blocked without style-src: 'unsafe-inline' (which is the unsafe CSP).

old.setAttribute('style', m.oldValue);

For any apps that pull in the affected versions and have a strict CSP, this issue will generate a very large numbers of errors like the one below (one for each time that line of code runs). As a possible side effect, any error reporting services or report-url endpoints may be quickly overwhelmed with error reports.

image

@razor-x
Copy link
Author

razor-x commented Feb 3, 2022

@eoghanmurray The tech for this project is a bit beyond my area of knowledge, but since you are the original owner of the PR, I was wondering if you have any thoughts on workarounds. Would it be possible to implement this using a data attribute like data-style instead of style on the app you are recording? I don't think CSP will care about data attributes.

@Juice10
Copy link
Contributor

Juice10 commented Feb 4, 2022

@razor-x would you mind if we stripped all the CSP policies on replay? I think that would solve this issue for you.

@razor-x
Copy link
Author

razor-x commented Feb 4, 2022

@razor-x would you mind if we stripped all the CSP policies on replay? I think that would solve this issue for you.

I'm not sure I understand this proposal. Can you point at an example?

To further clarify, this is an issue when the DOM is being recorded not replayed. As I understand things, as long as there is JS code that tries to write style attributes it will conflict with a strict CSP.

@razor-x
Copy link
Author

razor-x commented Feb 16, 2022

This is what I am thinking might work, just read and write to a different attribute. Not sure what other spots if any would need an update, I tired to use the other PR to see what might need to change: rxfork@1d6d8a1

(I'd take this further, but I tried for a bit to get the tests passing on my local but hit various errors and had to give up.)

image

@eoghanmurray
Copy link
Contributor

Thanks for alerting me on this!
The data-style solution wouldn't work as the style attribute is special and has an API associated with it (old.style.getPropertyValue).
The this.doc.createElement('span') bit is just to create a dummy element so we can access this API (the style attribute comes into the mutation as text information).
We'll need to come up with something better than this.doc.createElement (this did bother me at the time, as this is in the recording!)

I wonder do we need to go so far as creating an iframe object (could that have a different CSP policy) and executing createElement within that? Would that be something you could check? Or let me know how to create a document with this type of restrictive CSP policy.

@eoghanmurray
Copy link
Contributor

eoghanmurray commented Feb 24, 2022

@razor-x would you mind if we stripped all the CSP policies on replay? I think that would solve this issue for you.

@Juice10 This is on the record side; we are creating and discarding an anonymous here just to access it's style attribute.

@eoghanmurray
Copy link
Contributor

eoghanmurray commented Feb 24, 2022

@razor-x how does the document itself modify the style in the first place? (the original modification that generated the mutation)
Could you have a look at the calling code for that and check how it's actually doing it?

(via dev tools > inspector > (the element) > break on attribute modifications)

@razor-x
Copy link
Author

razor-x commented Feb 24, 2022

@razor-x how does the document itself modify the style in the first place? (the original modification that generated the mutation) Could you have a look at the calling code for that and check how it's actually doing it?

(via dev tools > inspector > (the element) > break on attribute modifications)

Sure. Just some more context on how I discovered the issue. I recently updated our app to MUI v5 which is supposed to have strict CSP compatibility now (since they switched to emotion / styled-components and no longer use CSS in JS). I enabled the strict CSP headers and tested the site in staging where we are NOT running rrweb and saw no errors. When moved to prod where recording is enabled, I saw the CSP errors triggered by the referenced mutation line from rrweb.

I actually would expect the app's attribute updates to trigger CSP but there must be a reason they are allowed.

Here is one of the things triggering a modification that gets picked up by the rrweb mutation.

image

image

@razor-x
Copy link
Author

razor-x commented Feb 24, 2022

I loaded it up in dev mode and grabbed the non-minified react code that it breaks on.

image

@eoghanmurray
Copy link
Contributor

eoghanmurray commented Feb 25, 2022

node.style.transition = theme.transitions.create('opacity', transitionProps);

Ok so maybe it's okay to access the style property but not set the attribute?

(I'm ignoring the second screenshot as the attribute being set there is aria-owns and not style)

In terms of speculative investigation, could you check whether something like the following is permissable in your CSP context (you can paste it in in the console and see what errors arise):

var throwaway = document.createElement('iframe');
throwaway.setAttribute('sandbox', 'allow-same-origin allow-scripts');  // if it works, I'd also want to know if it works without this!
var sp = throwaway.contentDocument.createElement('span');
sp.setAttribute('style', 'background:black;');

@razor-x
Copy link
Author

razor-x commented Feb 25, 2022

As a sanity check I deployed the restrictive CSP back to my testing environment and confirmed the (non-rrweb) updates do not trigger violations in chrome or firefox. I also ran your scripts against that.

(I'm ignoring the second screenshot as the attribute being set there is aria-owns and not style)

Ah good catch, I played to the other breaks, hopefully this is move useful. I think the first one it the style that makes the box appear and the second is the box being hidden.

image

image

In terms of speculative investigation, could you check whether something like the following is permissable in your CSP context (you can paste it in in the console and see what errors arise):

var throwaway = document.createElement('iframe');
throwaway.setAttribute('sandbox', 'allow-same-origin allow-scripts');  // if it works, I'd also want to know if it works without this!
var sp = throwaway.contentDocument.createElement('span');
sp.setAttribute('style', 'background:black;');

There maybe an issue with these, I got non-CSP errors in all cases.

chrome

image

firefox

image

Then as a control I tried this on https://example.com/

image

@razor-x
Copy link
Author

razor-x commented Feb 25, 2022

I modified the script and tried again

var throwaway = document.createElement('iframe');
throwaway.setAttribute('sandbox', 'allow-same-origin allow-scripts');  // if it works, I'd also want to know if it works without this!
document.body.appendChild(throwaway);
var sp = throwaway.contentDocument.createElement('span');
sp.setAttribute('style', 'background:black;');

example.com

image

With strict CSP

image

@razor-x
Copy link
Author

razor-x commented Feb 25, 2022

I did some digging and I suspect the key may be that style updates using the CSSOM by an already-allowed CSP script are allowed without unsafe-inline.

Here's what's I found that seems to suggest this:

@eoghanmurray
Copy link
Contributor

right, contentDocument isn't available until the iframe is appended to the page; I thought I got the opposite result while testing but must have accidentally added my variable to the page or reused one or something.

Could you try simpler:

var throwaway = new Document();
var sp = throwaway.createElement('span');
sp.setAttribute('style', 'background:black;');

I imagine the CSP is inherited by the document, but maybe not given the new document isn't actually attached to anything?

@eoghanmurray
Copy link
Contributor

(I'd use the CSSOM, but the old style attribute is provided as a string, and we'd have to loop through it to parse it, which I'm not confident we'd get right for whatever edge cases - setting the attribute lets the css engine do this work!)

@razor-x
Copy link
Author

razor-x commented Feb 25, 2022

right, contentDocument isn't available until the iframe is appended to the page; I thought I got the opposite result while testing but must have accidentally added my variable to the page or reused one or something.

Could you try simpler:

var throwaway = new Document();
var sp = throwaway.createElement('span');
sp.setAttribute('style', 'background:black;');

I imagine the CSP is inherited by the document, but maybe not given the new document isn't actually attached to anything?

This might actually work since as you said, the document is not actually rendering into the page! (I did both together to show the no-error / error cases in one place).

image

---- quick edit, showing the attribute update did get saved

image

eoghanmurray added a commit to statcounter/rrweb that referenced this issue Feb 26, 2022
@eoghanmurray
Copy link
Contributor

I coded this up in #846 but haven't tested it or anything!

@razor-x
Copy link
Author

razor-x commented Mar 1, 2022

Nice, I hope it's this simple. What's the best way for us to test this? I was never able to get the project dev env running on my local. I think the CSP will be fine now, so we just need to check the recoding / replay right?

@eoghanmurray
Copy link
Contributor

Would you be able to have another go at setting up a dev environment and let the core team know if there were any instructions that weren't clear or were misleading?
This is a priority for me to ensure our dev instructions are better but the people with the most insight into this are the ones setting things up for the first time.

eoghanmurray added a commit to statcounter/rrweb that referenced this issue Mar 2, 2022
@razor-x
Copy link
Author

razor-x commented Mar 2, 2022

Would you be able to have another go at setting up a dev environment and let the core team know if there were any instructions that weren't clear or were misleading? This is a priority for me to ensure our dev instructions are better but the people with the most insight into this are the ones setting things up for the first time.

I totally understand this. So my first check before hacking on most projects is to make sure all the tests pass before I change anything. Otherwise I can't really know if my changes broke or fixed anything useful. It seems like, looking at the docs and the travis config that I should be able to run on Node 12 (IMO the node version to develop on should be in package.json or in README or .nvmrc) and just do yarn then yarn test and expect it to work (as long as master CI is green upstream). I don't see any other external dependencies listed beyond that. Unfortunately this fails and I don't have much else to go on to fix it. See log below and let me know if you want to move this to a different issue.

CLI log
~/forks/rrweb master
❯ git clean -fdx
n
~/forks/rrweb master
❯ nvm i lts/erbium
v12.22.10 is already installed.
Now using node v12.22.10 (npm v6.14.16)

~/forks/rrweb master
❯ yarn
yarn install v1.22.17
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 211.12s.

~/forks/rrweb master 3m 32s
❯ uname -a
Linux Mjolnir 5.16.10-arch1-1 #1 SMP PREEMPT Wed, 16 Feb 2022 19:35:18 +0000 x86_64 GNU/Linux

~/forks/rrweb master
❯ yarn test
yarn run v1.22.17
$ yarn lerna run test
$ lerna run test
lerna notice cli v4.0.0
lerna info versioning independent
lerna info Executing command in 3 packages: "yarn run test"
lerna ERR! yarn run test exited 1 in 'rrweb-snapshot'
lerna ERR! yarn run test stdout:
$ jest
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
lerna ERR! yarn run test stderr:
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
PASS test/css.test.ts (6.895 s)
PASS test/rebuild.test.ts (7.202 s)
PASS test/snapshot.test.ts (8.352 s)
FAIL test/integration.test.ts (48.476 s)
  ● integration tests › [html file]: about-mozilla.html

    Protocol error (Target.createTarget): Target closed.

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at ../../node_modules/puppeteer/lib/Connection.js:74:56
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:73:12)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: basic.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: block-element.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: compat-mode.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: cors-style-sheet.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: dynamic-stylesheet.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: form-fields.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: hover.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: iframe-inner.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: iframe.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: invalid-attribute.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: invalid-doctype.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: invalid-tagname.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: mask-text.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: picture.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: preload.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: shadow-dom.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: svg.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: video.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: with-relative-res.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: with-script.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: with-style-sheet-with-import.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › [html file]: with-style-sheet.html

    WebSocket is not open: readyState 3 (CLOSED)

       96 |     const title = '[html file]: ' + html.filePath;
       97 |     it(title, async () => {
    >  98 |       const page: puppeteer.Page = await browser.newPage();
          |                                                  ^
       99 |       // console for debug
      100 |       // tslint:disable-next-line: no-console
      101 |       page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:98:50
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:98:50
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:97:26)

  ● integration tests › correctly triggers backCompat mode and rendering

    WebSocket is not open: readyState 3 (CLOSED)

      146 |
      147 |   it('correctly triggers backCompat mode and rendering', async () => {
    > 148 |     const page: puppeteer.Page = await browser.newPage();
          |                                                ^
      149 |     // console for debug
      150 |     // tslint:disable-next-line: no-console
      151 |     page.on('console', (msg) => console.log(msg.text()));

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:148:48
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:148:48
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:147:69)

  ● integration tests › correctly saves images offline

    WebSocket is not open: readyState 3 (CLOSED)

      194 |
      195 |   it('correctly saves images offline', async () => {
    > 196 |     const page: puppeteer.Page = await browser.newPage();
          |                                                ^
      197 |
      198 |     await page.goto('http://localhost:3030/html/picture.html', {
      199 |       waitUntil: 'load',

      at WebSocket.send (../../node_modules/puppeteer/node_modules/ws/lib/websocket.js:329:19)
      at WebSocketTransport.send (../../node_modules/puppeteer/lib/WebSocketTransport.js:60:14)
      at Connection._rawSend (../../node_modules/puppeteer/lib/Connection.js:86:21)
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:72:21)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:196:48
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:196:48
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:195:51)

  ● iframe integration tests › snapshot async iframes

    thrown: "Exceeded timeout of 30000 ms for a test.
    Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."

      244 |   });
      245 |
    > 246 |   it('snapshot async iframes', async () => {
          |   ^
      247 |     const page: puppeteer.Page = await browser.newPage();
      248 |     // console for debug
      249 |     // tslint:disable-next-line: no-console

      at test/integration.test.ts:246:3
      at Object.<anonymous> (test/integration.test.ts:216:1)

  ● shadow DOM integration tests › snapshot shadow DOM

    Protocol error (Target.createTarget): Target closed.

      294 |
      295 |   it('snapshot shadow DOM', async () => {
    > 296 |     const page: puppeteer.Page = await browser.newPage();
          |                                                ^
      297 |     // console for debug
      298 |     // tslint:disable-next-line: no-console
      299 |     page.on('console', (msg) => console.log(msg.text()));

      at ../../node_modules/puppeteer/lib/Connection.js:74:56
      at Connection.send (../../node_modules/puppeteer/lib/Connection.js:73:12)
      at Browser._createPageInContext (../../node_modules/puppeteer/lib/Browser.js:174:47)
      at BrowserContext.newPage (../../node_modules/puppeteer/lib/Browser.js:367:26)
      at Browser.newPage (../../node_modules/puppeteer/lib/Browser.js:166:33)
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:112:23)
      at test/integration.test.ts:296:48
      at test/integration.test.ts:8:71
        -- ASYNC --
      at Browser.<anonymous> (../../node_modules/puppeteer/lib/helper.js:111:15)
      at test/integration.test.ts:296:48
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at Object.<anonymous> (test/integration.test.ts:295:40)

Test Suites: 1 failed, 3 passed, 4 total
Tests:       27 failed, 31 passed, 58 total
Snapshots:   0 total
Time:        48.995 s
Ran all test suites.
error Command failed with exit code 1.
lerna ERR! yarn run test exited 1 in 'rrweb-snapshot'
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

~/forks/rrweb master 53s
❯

@eoghanmurray
Copy link
Contributor

Websocket is not open

I imagine the testing suite interacts with puppeteer over websockets or something.

Can you check the version of puppeteer you have installed?

@Juice10 any ideas?

@Juice10
Copy link
Contributor

Juice10 commented Mar 3, 2022

@eoghanmurray We are using quite an old version of puppeteer. Might be worth upgrading it just to see if this disappears.

eoghanmurray added a commit to statcounter/rrweb that referenced this issue Mar 3, 2022
@razor-x
Copy link
Author

razor-x commented Mar 4, 2022

Here is some more feedback after going a little further.

I tried to run yarn test in just the packages/rrweb directory but I got a bunch of errors. I thought maybe this was because I did not run yarn dev first, so I tried that and it seemed to work, but then web app just loaded a blank page, so not sure what to do with that (see screenshots). I tried to rerun the packages/rrweb tests again but same errors as before.

2022-03-03_20-12_1

2022-03-03_20-12

Errors on yarn test for packages/rrweb
~/forks/rrweb/packages/rrweb master
❯ yarn test
yarn run v1.22.17
$ npm run bundle:browser && jest
npm WARN lifecycle The node binary used for scripts is /tmp/yarn--1646367149857-0.5009724335193326/node but npm is using /home/razorx/.local/share/nvm/versions/node/v12.22.10/bin/node itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.

> rrweb@1.1.2 bundle:browser /home/razorx/forks/rrweb/packages/rrweb
> cross-env BROWSER_ONLY=true rollup --config


./src/index.ts → dist/rrweb.min.js...
created dist/rrweb.min.js in 8.5s

./src/plugins/console/record/index.ts → dist/plugins/console-record.min.js...
created dist/plugins/console-record.min.js in 4.5s
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
 FAIL  test/replay/webgl.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/replay/webgl.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 PASS  test/packer.test.ts (8.493 s)
 FAIL  test/record/webgl.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/record/webgl.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/e2e/webgl.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/e2e/webgl.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/machine.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/machine.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/replay/deserialize-args.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/replay/deserialize-args.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/record/serialize-args.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/record/serialize-args.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/replayer.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/replayer.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/integration.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/integration.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/record.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/record.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/replay/preload-all-images.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/replay/preload-all-images.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 FAIL  test/replay/webgl-mutation.test.ts
  ● Test suite failed to run

    Cannot find module 'rrweb-snapshot' from 'test/utils.ts'

    Require stack:
      test/utils.ts
      test/replay/webgl-mutation.test.ts

    > 1 | import { NodeType } from 'rrweb-snapshot';
        | ^
      2 | import {
      3 |   EventType,
      4 |   IncrementalSource,

      at Resolver.resolveModule (../../node_modules/jest-resolve/build/resolver.js:322:11)
      at Object.<anonymous> (test/utils.ts:1:1)

 PASS  test/replay/virtual-styles.test.ts (9.951 s)

Test Suites: 11 failed, 2 passed, 13 total
Tests:       1 skipped, 11 passed, 12 total
Snapshots:   1 passed, 1 total
Time:        10.573 s, estimated 14 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

~/forks/rrweb/packages/rrweb master 26s
❯

@Juice10
Copy link
Contributor

Juice10 commented Mar 4, 2022

This looks a bit like you haven't run yarn install in the root directory. Could you run yarn install, and then maybe yarn build:all just in case.
If you run yarn test in the package/rrweb directory after that some of these errors should disappear.

@razor-x
Copy link
Author

razor-x commented Mar 4, 2022

This looks a bit like you haven't run yarn install in the root directory. Could you run yarn install, and then maybe yarn build:all just in case. If you run yarn test in the package/rrweb directory after that some of these errors should disappear.

yarn install did not change the result (I had run this before anyway). Running yarn build:all in the root did let me run the tests inside packages/rrweb but they failed with new errors, see below:

Test errors
❯ cd ~/forks/rrweb

~/forks/rrweb master
❯ nvm i lts/erbium
v12.22.10 is already installed.
yarNow using node v12.22.10 (npm v6.14.16)
n
~/forks/rrweb master
❯ yarn
yarn install v1.22.17
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.95s.

~/forks/rrweb master
❯ yarn build:all
yarn run v1.22.17
$ yarn lerna run prepublish
$ lerna run prepublish
lerna notice cli v4.0.0
lerna info versioning independent
lerna info Executing command in 4 packages: "yarn run prepublish"
lerna info run Ran npm script 'prepublish' in 'rrweb-snapshot' in 20.3s:
$ npm run typings && npm run bundle

> rrweb-snapshot@1.1.13 typings /home/razorx/forks/rrweb/packages/rrweb-snapshot
> tsc -d --declarationDir typings


> rrweb-snapshot@1.1.13 bundle /home/razorx/forks/rrweb/packages/rrweb-snapshot
> rollup --config

lerna info run Ran npm script 'prepublish' in 'rrdom' in 24.6s:
$ npm run bundle

> rrdom@0.1.1 bundle /home/razorx/forks/rrweb/packages/rrdom
> rollup --config

lerna info run Ran npm script 'prepublish' in 'rrweb' in 70.7s:
$ npm run typings && npm run bundle

> rrweb@1.1.2 typings /home/razorx/forks/rrweb/packages/rrweb
> tsc -d --declarationDir typings


> rrweb@1.1.2 bundle /home/razorx/forks/rrweb/packages/rrweb
> rollup --config

lerna info run Ran npm script 'prepublish' in 'rrweb-player' in 25.2s:
$ yarn build
$ rollup -c
lerna success run Ran npm script 'prepublish' in 4 packages in 116.2s:
lerna success - rrdom
lerna success - rrweb
lerna success - rrweb-player
lerna success - rrweb-snapshot
Done in 117.09s.

~/forks/rrweb master 1m 57s
❯ cd packages/rrweb

~/forks/rrweb/packages/rrweb master
❯ yarn test
yarn run v1.22.17
$ npm run bundle:browser && jest
npm WARN lifecycle The node binary used for scripts is /tmp/yarn--1646415871253-0.6312769413686468/node but npm is using /home/razorx/.local/share/nvm/versions/node/v12.22.10/bin/node itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.

> rrweb@1.1.2 bundle:browser /home/razorx/forks/rrweb/packages/rrweb
> cross-env BROWSER_ONLY=true rollup --config


./src/index.ts → dist/rrweb.min.js...
created dist/rrweb.min.js in 8.5s

./src/plugins/console/record/index.ts → dist/plugins/console-record.min.js...
created dist/plugins/console-record.min.js in 4.4s
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`). See https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/#easier-ecmascript-module-interoperability for more information.
 PASS  test/packer.test.ts (7.304 s)
 PASS  test/replay/virtual-styles.test.ts (9.73 s)
 FAIL  test/record/webgl.test.ts (10.977 s)
  ● record webgl › will record changes to a canvas element

    socket hang up



  ● record webgl › will record changes to a canvas element

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › will record changes to a webgl2 canvas element

    socket hang up



  ● record webgl › will record changes to a webgl2 canvas element

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › will record changes to a canvas element before the canvas gets added

    socket hang up



  ● record webgl › will record changes to a canvas element before the canvas gets added

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › will record changes to a canvas element before the canvas gets added (webgl2)

    socket hang up



  ● record webgl › will record changes to a canvas element before the canvas gets added (webgl2)

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › will record webgl variables

    socket hang up



  ● record webgl › will record webgl variables

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › will record webgl variables in reverse order

    socket hang up



  ● record webgl › will record webgl variables in reverse order

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › sets _context on canvas.getContext()

    socket hang up



  ● record webgl › sets _context on canvas.getContext()

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › only sets _context on first canvas.getContext() call

    socket hang up



  ● record webgl › only sets _context on first canvas.getContext() call

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)

  ● record webgl › should batch events by RAF

    socket hang up



  ● record webgl › should batch events by RAF

    TypeError: Cannot read property 'close' of undefined

      67 |
      68 |   afterEach(async () => {
    > 69 |     await ctx.page.close();
         |                    ^
      70 |   });
      71 |
      72 |   afterAll(async () => {

      at test/record/webgl.test.ts:69:20
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at Object.<anonymous> (test/record/webgl.test.ts:68:13)


  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      71 |
      72 |   afterAll(async () => {
    > 73 |     await ctx.browser.close();
         |                       ^
      74 |   });
      75 |
      76 |   return ctx;

      at test/record/webgl.test.ts:73:23
      at step (test/record/webgl.test.ts:34:23)
      at Object.next (test/record/webgl.test.ts:15:53)
      at test/record/webgl.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record/webgl.test.ts:5:12)
      at test/record/webgl.test.ts:72:12

 PASS  test/machine.test.ts
 PASS  test/replay/deserialize-args.test.ts (11.979 s)
 PASS  test/replay/webgl-mutation.test.ts
 FAIL  test/e2e/webgl.test.ts
  ● e2e webgl › will record and replay a webgl square

    socket hang up



  ● e2e webgl › will record and replay a webgl square

    TypeError: Cannot read property 'close' of undefined

      45 |
      46 |   afterEach(async () => {
    > 47 |     await page.close();
         |                ^
      48 |   });
      49 |
      50 |   afterAll(async () => {

      at test/e2e/webgl.test.ts:47:16
      at step (test/e2e/webgl.test.ts:33:23)
      at Object.next (test/e2e/webgl.test.ts:14:53)
      at test/e2e/webgl.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/e2e/webgl.test.ts:4:12)
      at Object.<anonymous> (test/e2e/webgl.test.ts:46:13)

  ● e2e webgl › will record and replay a webgl image

    socket hang up



  ● e2e webgl › will record and replay a webgl image

    TypeError: Cannot read property 'close' of undefined

      45 |
      46 |   afterEach(async () => {
    > 47 |     await page.close();
         |                ^
      48 |   });
      49 |
      50 |   afterAll(async () => {

      at test/e2e/webgl.test.ts:47:16
      at step (test/e2e/webgl.test.ts:33:23)
      at Object.next (test/e2e/webgl.test.ts:14:53)
      at test/e2e/webgl.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/e2e/webgl.test.ts:4:12)
      at Object.<anonymous> (test/e2e/webgl.test.ts:46:13)


  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      50 |   afterAll(async () => {
      51 |     await server.close();
    > 52 |     await browser.close();
         |                   ^
      53 |   });
      54 |
      55 |   const getHtml = (

      at test/e2e/webgl.test.ts:52:19
      at step (test/e2e/webgl.test.ts:33:23)
      at Object.next (test/e2e/webgl.test.ts:14:53)
      at fulfilled (test/e2e/webgl.test.ts:5:58)

 PASS  test/record/serialize-args.test.ts (13.035 s)
 FAIL  test/replay/webgl.test.ts (14.044 s)
  ● replayer › webgl › should output simple webgl object

    socket hang up



  ● replayer › webgl › should output simple webgl object

    TypeError: Cannot read property 'close' of undefined

      43 |
      44 |   afterEach(async () => {
    > 45 |     await page.close();
         |                ^
      46 |   });
      47 |
      48 |   afterAll(async () => {

      at test/replay/webgl.test.ts:45:16
      at step (test/replay/webgl.test.ts:33:23)
      at Object.next (test/replay/webgl.test.ts:14:53)
      at test/replay/webgl.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/replay/webgl.test.ts:4:12)
      at Object.<anonymous> (test/replay/webgl.test.ts:44:13)


  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      47 |
      48 |   afterAll(async () => {
    > 49 |     await browser.close();
         |                   ^
      50 |   });
      51 |
      52 |   describe('webgl', () => {

      at test/replay/webgl.test.ts:49:19
      at step (test/replay/webgl.test.ts:33:23)
      at Object.next (test/replay/webgl.test.ts:14:53)
      at test/replay/webgl.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/replay/webgl.test.ts:4:12)
      at test/replay/webgl.test.ts:48:12

 FAIL  test/integration.test.ts
  ● record integration tests › can record form interactions

    socket hang up



  ● record integration tests › can record childList mutations

    socket hang up



  ● record integration tests › can record character data muatations

    socket hang up



  ● record integration tests › can record attribute mutation

    socket hang up



  ● record integration tests › can record node mutations

    socket hang up



  ● record integration tests › can freeze mutations

    socket hang up



  ● record integration tests › should not record input events on ignored elements

    socket hang up



  ● record integration tests › should not record input values if maskAllInputs is enabled

    socket hang up



  ● record integration tests › can use maskInputOptions to configure which type of inputs should be masked

    socket hang up



  ● record integration tests › should mask value attribute with maskInputOptions

    socket hang up



  ● record integration tests › should record input userTriggered values if userTriggeredOnInput is enabled

    socket hang up



  ● record integration tests › should not record blocked elements and its child nodes

    socket hang up



  ● record integration tests › should not record blocked elements dynamically added

    socket hang up



  ● record integration tests › should record DOM node movement 1

    socket hang up



  ● record integration tests › should record DOM node movement 2

    socket hang up



  ● record integration tests › should record dynamic CSS changes

    socket hang up



  ● record integration tests › should record canvas mutations

    socket hang up



  ● record integration tests › should record webgl canvas mutations

    socket hang up



  ● record integration tests › will serialize node before record

    socket hang up



  ● record integration tests › will defer missing next node mutation

    socket hang up



  ● record integration tests › should record console messages

    socket hang up



  ● record integration tests › should nest record iframe

    socket hang up



  ● record integration tests › should record shadow DOM

    socket hang up



  ● record integration tests › should mask texts

    socket hang up



  ● record integration tests › should mask texts using maskTextFn

    socket hang up



  ● record integration tests › can mask character data mutations

    socket hang up




  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      80 |
      81 |   afterAll(async () => {
    > 82 |     await browser.close();
         |                   ^
      83 |     server.close();
      84 |   });
      85 |

      at test/integration.test.ts:82:19
      at step (test/integration.test.ts:33:23)
      at Object.next (test/integration.test.ts:14:53)
      at test/integration.test.ts:8:71
      at Object.<anonymous>.__awaiter (test/integration.test.ts:4:12)
      at test/integration.test.ts:81:12

 PASS  test/replay/preload-all-images.test.ts (14.975 s)
 FAIL  test/record.test.ts
  ● record › will only have one full snapshot without checkout config

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › will only have one full snapshot without checkout config

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › can checkout full snapshot by count

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › can checkout full snapshot by count

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › can checkout full snapshot by time

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › can checkout full snapshot by time

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › is safe to checkout during async callbacks

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › is safe to checkout during async callbacks

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › can add custom event

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › can add custom event

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › captures stylesheet rules

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › captures stylesheet rules

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › captures nested stylesheet rules

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › captures nested stylesheet rules

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › without CSSGroupingRule support › captures nested stylesheet rules

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › without CSSGroupingRule support › captures nested stylesheet rules

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record › captures style property changes

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record › captures style property changes

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record iframes › captures iframe content in correct order

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record iframes › captures iframe content in correct order

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)

  ● record iframes › captures stylesheet mutations in iframes

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● record iframes › captures stylesheet mutations in iframes

    TypeError: Cannot read property 'close' of undefined

      58 |
      59 |   afterEach(async () => {
    > 60 |     await ctx.page.close();
         |                    ^
      61 |   });
      62 |
      63 |   afterAll(async () => {

      at test/record.test.ts:60:20
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at Object.<anonymous> (test/record.test.ts:59:13)


  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      62 |
      63 |   afterAll(async () => {
    > 64 |     await ctx.browser.close();
         |                       ^
      65 |   });
      66 |
      67 |   return ctx;

      at test/record.test.ts:64:23
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at test/record.test.ts:63:12

  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      62 |
      63 |   afterAll(async () => {
    > 64 |     await ctx.browser.close();
         |                       ^
      65 |   });
      66 |
      67 |   return ctx;

      at test/record.test.ts:64:23
      at step (test/record.test.ts:34:23)
      at Object.next (test/record.test.ts:15:53)
      at test/record.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/record.test.ts:5:12)
      at test/record.test.ts:63:12

 FAIL  test/replayer.test.ts (6.577 s)
  ● replayer › can get meta data

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can get meta data

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › will start actions when play

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › will start actions when play

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › will clean actions when pause

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › will clean actions when pause

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can play at any time offset

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can play at any time offset

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can play a second time in the future

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can play a second time in the future

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can play a second time to the past

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can play a second time to the past

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can pause at any time offset

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can pause at any time offset

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can fast forward past StyleSheetRule changes on virtual elements

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can fast forward past StyleSheetRule changes on virtual elements

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › should apply fast forwarded StyleSheetRules that where added

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › should apply fast forwarded StyleSheetRules that where added

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can handle removing style elements

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can handle removing style elements

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can fast forward past StyleSheetRule deletion on virtual elements

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can fast forward past StyleSheetRule deletion on virtual elements

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › should delete fast forwarded StyleSheetRules that where removed

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › should delete fast forwarded StyleSheetRules that where removed

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can fast-forward mutation events containing nested iframe elements

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can fast-forward mutation events containing nested iframe elements

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › can stream events in live mode

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › can stream events in live mode

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › replays same timestamp events in correct order

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › replays same timestamp events in correct order

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)

  ● replayer › replays same timestamp events in correct order (with addAction)

    Protocol error (Target.setDiscoverTargets): Target closed.

      at node_modules/puppeteer/src/common/Connection.ts:102:57
      at Connection.send (node_modules/puppeteer/src/common/Connection.ts:101:12)
      at Function.create (node_modules/puppeteer/src/common/Browser.ts:211:22)
      at ChromeLauncher.launch (node_modules/puppeteer/src/node/Launcher.ts:142:37)

  ● replayer › replays same timestamp events in correct order (with addAction)

    TypeError: Cannot read property 'close' of undefined

      44 |
      45 |   afterEach(async () => {
    > 46 |     await page.close();
         |                ^
      47 |   });
      48 |
      49 |   afterAll(async () => {

      at test/replayer.test.ts:46:16
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at Object.<anonymous> (test/replayer.test.ts:45:13)


  ● Test suite failed to run

    TypeError: Cannot read property 'close' of undefined

      48 |
      49 |   afterAll(async () => {
    > 50 |     await browser.close();
         |                   ^
      51 |   });
      52 |
      53 |   it('can get meta data', async () => {

      at test/replayer.test.ts:50:19
      at step (test/replayer.test.ts:34:23)
      at Object.next (test/replayer.test.ts:15:53)
      at test/replayer.test.ts:9:71
      at Object.<anonymous>.__awaiter (test/replayer.test.ts:5:12)
      at test/replayer.test.ts:49:12

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks.
Test Suites: 6 failed, 7 passed, 13 total
Tests:       65 failed, 1 skipped, 41 passed, 107 total
Snapshots:   1 passed, 1 total
Time:        19.04 s
Ran all test suites.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

~/forks/rrweb/packages/rrweb master 35s
❯

@razor-x
Copy link
Author

razor-x commented Apr 1, 2022

Seems like this stalled out a bit on the testing front. Sorry I wasn't able to get this running locally but the fix seems so simple. Any way we can quickly validate it works?

@eoghanmurray
Copy link
Contributor

I'm agnostic; just not sure if #846 actually fixes it ... presume it does.
If possible, a general CSP test would be good to catch regression on this, or the emergence of new CSP violations.

AntonioStipic added a commit to Analyzee/rrweb that referenced this issue Jan 5, 2023
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Mar 27, 2023
@eoghanmurray
Copy link
Contributor

@razor-x I've fixed up the conflict — we are trying to be more proactive about merging PRs, so if you could have another look at #846 to get an extra set of eyes on it, e.g. have you been running that patch in production or anything?

eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Apr 3, 2023
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Apr 3, 2023
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Apr 12, 2023
@eoghanmurray
Copy link
Contributor

Our test suite was able to validate that it didn't work — I've added some commits today to make it actually work so #846 might be able to land in trunk soon.

eoghanmurray added a commit to statcounter/rrweb that referenced this issue Apr 13, 2023
eoghanmurray added a commit to statcounter/rrweb that referenced this issue Apr 13, 2023
YunFeng0817 pushed a commit that referenced this issue May 22, 2023
* Fix for #816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Jul 27, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Jul 27, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Jul 27, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Aug 3, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Aug 8, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
eoghanmurray added a commit to eoghanmurray/rrweb that referenced this issue Aug 8, 2023
* Fix for rrweb-io#816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')`

* The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available

* Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available
@sneko
Copy link

sneko commented Mar 11, 2024

I don't have the whole context but from what I understand you could modify an element with element.style.color = 'red'; instead of dealing with its attribute (the latter triggering the CSP).

In the meantime, my workaround is to use style-src-attr 'unsafe-inline' instead of doing it on style-src which would break in case of already using a nonce for third-party files.

@daibhin
Copy link
Contributor

daibhin commented Jun 25, 2024

What is the status of this issue? I am working on an issue where rrweb styles are being dropped in a Svelte app and I'm wondering if it could be related to this. Happy to test / patch anything in production that might help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants