Skip to content

Chrome/Edge >=146 throws: TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element') #8493

@htho

Description

@htho

What is your Scenario?

Our tests run on a (self-hosted) headless azure-pipeline agent.
They started to fail when we updated the browsers to Chrome/Edge 146.
I can't reproduce the problem locally.
The problem appears for tests in our on-premise application - not for very basic pages.
Hence I can't create a minimal working example, because I have no way to properly debug the app, when the error occurs.

What is the Current behavior?

About 90% of our tests fail on one of the first actions/assertions of the test.

The error message is:

      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

BTW: The stack trace is only available if I run chrome with the --disable-web-security flag.

What is the Expected behavior?

The tests should not fail because of the exception in Hammerhead.
There should not be an exception like this in Hammerhead.

What is the public URL of the test page? (attach your complete example)

  • There is none
  • This is a complex on-premise application
  • I cant create a minimal working example because the tests only fail in our pipeline, where I can't use a debugger.

What is your TestCafe test code?

import { Selector } from "testcafe";

fixture("Dummy")
	.page(`http://localhost:16700/index.htm`)
	.before(async() => {
		// a simplification to report the bug
		await new Promise<void>((resolve, reject) => {
			setTimeout(resolve, 120_000);
		});
	})
	.beforeEach(async(t) => {
		// await t.debug();
		await t.resizeWindow(1024, 768);
	})
	.afterEach(async(t) => {
		// we need this later
		console.log(await t.getBrowserConsoleMessages());
	});

for (let i = 1; i <= 10; i++) {
	test(`test (Attempt #${i})`, async(t) => {
		await t.expect(Selector(`[pweb-name="NavigationCurrentView"]`).textContent).eql("0");
	});
}

Your complete configuration file

none

Your complete test report

> testcafe chrome:"azure-pipelines/PortableBrowsers/chrome/chrome-146-72/GoogleChromePortable.exe --disable-web-security" --headless ./Integrationstestprojekte/WebVisuPictures/dummy.tc.ts

 Running tests in:
 - Chrome 146.0.0.0 / Windows Server 2022

 Dummy
{ log: [], info: [], warn: [], error: [] }
 √ test (Attempt #1)
 × test (Attempt #2)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #3)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #4)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #5)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #6)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #7)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #8)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #9)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)


 × test (Attempt #10)

   1) - Error in fixture.beforeEach hook -
      A JavaScript error occurred on "http://localhost:16700/index.htm".
      Repeat test actions in the browser and check the console for errors.
      Enable the “skipJsErrors” option to ignore JavaScript errors during test execution. Learn more: "https://testcafe.io/documentation/404038/recipes/debugging/skip-javascript-errors"
      If the website only throws this error when you test it with TestCafe, please create a new issue at:
      "https://github.com/DevExpress/testcafe/issues/new?template=bug-report.md".

      JavaScript error details:
      TypeError: Cannot read properties of null (reading 'hammerhead|shadow-ui-element')
          at isShadowUIElement (http://localhost:56889/hammerhead.js:3583:22)
          at _onFocus (http://localhost:56889/hammerhead.js:40330:52)
          at http://localhost:56889/hammerhead.js:39672:34

      Browser: Chrome 146.0.0.0 / Windows Server 2022

          8 |            setTimeout(resolve, 120_000);
          9 |        });
         10 |    })
         11 |    .beforeEach(async(t) => {
         12 |        // await t.debug();
       > 13 |        await t.resizeWindow(1024, 768);
         14 |    })
         15 |    .afterEach(async(t) => {
         16 |        // we need this later
         17 |        console.log(await t.getBrowserConsoleMessages());
         18 |    });

         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:13:11)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:8:71)
         at __awaiter (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:4:12)
         at <anonymous> (C:\a\2\s\Integrationstestprojekte\WebVisuPictures\dummy.tc.ts:11:25)



 9/10 failed (2m 26s)

Screenshots

No response

Steps to Reproduce

none

TestCafe version

3.7.4

Node.js version

20.20.1

Command-line arguments

testcafe chrome:"azure-pipelines/PortableBrowsers/chrome/chrome-146-72/GoogleChromePortable.exe --disable-web-security" --headless ./Integrationstestprojekte/WebVisuPictures/dummy.tc.ts

Browser name(s) and version(s)

Chrome 146, Edge 146

Platform(s) and version(s)

Windows Server 2022

Other

I created a patch for testcafe-hammerhead, that fixes the problem and logs some debug-information:

diff --git a/node_modules/testcafe-hammerhead/lib/client/hammerhead.min.js b/node_modules/testcafe-hammerhead/lib/client/_hammerhead.min.js
similarity index 100%
rename from node_modules/testcafe-hammerhead/lib/client/hammerhead.min.js
rename to node_modules/testcafe-hammerhead/lib/client/_hammerhead.min.js
diff --git a/node_modules/testcafe-hammerhead/lib/client/hammerhead.js b/node_modules/testcafe-hammerhead/lib/client/hammerhead.js
index c01ff46..d0d65c3 100644
--- a/node_modules/testcafe-hammerhead/lib/client/hammerhead.js
+++ b/node_modules/testcafe-hammerhead/lib/client/hammerhead.js
@@ -3218,12 +3218,25 @@
 	    var doc = currentDocument || document;
 	    var activeElement = nativeMethods.documentActiveElementGetter.call(doc);
 	    var el = isDomElement(activeElement) ? activeElement : doc.body;
-	    while (el && el.shadowRoot) {
+		var result = el;
+	    while (result && result.shadowRoot) {
 	        // eslint-disable-next-line no-restricted-properties
-	        var shadowEl = el.shadowRoot.activeElement;
+	        var shadowEl = result.shadowRoot.activeElement;
 	        if (!shadowEl)
 	            break;
-	        el = shadowEl;
+	        result = shadowEl;
+	    }
+	    if(!result) {
+	        const info = {
+	            currentDocument: String(currentDocument),
+	            doc: String(doc),
+	            activeElement: String(activeElement),
+	            activeElementIsDomElement: String(isDomElement(activeElement)),
+	            el: String(el),
+	            result: String(result),
+	        }
+	        const err = new Error(`Unexpected nullish result for: getActiveElement(): ${JSON.stringify(info, null, 4)}`);
+	        console.error("getActiveElement", err.stack);
 	    }
 	    return el;
 	}
@@ -40327,6 +40340,11 @@
 	        this._onFocus = function (e) {
 	            var focusedEl = nativeMethods.eventTargetGetter.call(e);
 	            var activeEl = getActiveElement(document);
+	            if (activeEl === null) {
+	                const err = new Error(`getActiveElement() returned null for ${String(document)}!`);
+	                console.error("_onFocus", err.stack);
+	                return // gracefully return instead of throwing in isShadowUIElement(activeEl)
+	            };
 	            if (!isShadowUIElement(focusedEl) && !isShadowUIElement(activeEl))
 	                shadowUI.setLastActiveElement(activeEl);
 	        };

As a result, we log this:

getActiveElement Error: Unexpected nullish result for: getActiveElement(): {
    "currentDocument": "null",
    "doc": "[object HTMLDocument]",
    "activeElement": "null",
    "activeElementIsDomElement": "null",
    "el": "null",
    "result": "null"
}
    at getActiveElement (http://localhost:51773/hammerhead.js:3238:22)
    at _onFocus (http://localhost:51773/hammerhead.js:40342:29)
    at http://localhost:51773/hammerhead.js:39685:34


_onFocus Error: getActiveElement() returned null for null!
    at _onFocus (http://localhost:51773/hammerhead.js:40344:30)
    at http://localhost:51773/hammerhead.js:39685:34


getActiveElement Error: Unexpected nullish result for: getActiveElement(): {
    "currentDocument": "[object HTMLDocument]",
    "doc": "[object HTMLDocument]",
    "activeElement": "null",
    "activeElementIsDomElement": "null",
    "el": "null",
    "result": "null"
}
    at getActiveElement (http://localhost:51773/hammerhead.js:3238:22)
    at http://localhost:51773/hammerhead.js:39295:34
    at http://localhost:51773/hammerhead.js:39685:34

The problem is, that nativeMethods.documentActiveElementGetter.call(doc); returns null.

According to MDN null is a valid value:

If the focused element is within a document tree that's not descended from the current document (for example, the focused element is in the main document, and the invoking document is an embedded iframe), then this will be null.

I honestly don't know why this happens, but it is a valid value and should be handled properly.
IMO isShadowUIElement(element) should return false if element is null.

There are no iframes in our application.

Given that not all tests fail, I suppose this is a timing issue. Chrome 146 probably does things a little different, so this fails.
But of course this could also be a bug in chrome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TYPE: bugThe described behavior is considered as wrong (bug).

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions