Search code examples
reactjsjestjspuppeteerend-to-end

Using jest-dom matchers with puppeteer objects


I'm writing end-to-end tests for a React application using puppeteer and jest.

I've extended the expectation matchers by importing @testing-library/jest-dom/extend-expect, and I encounter an error received value must be an HTMLElement or an SVGElement when I try to use one of the imported matchers on an object from puppeteer.

let bg = await page.waitForSelector('#bg'); // puppeteer
expect(bg).toBeVisible(); // jest
received value must be an HTMLElement or an SVGElement.
    Received has type:  object
    Received has value: {"_client": {"_callbacks": [Map], "_connection": [Connection], "_sessionId": "B2257B3009305E280640F675C248F61E", "_targetType": "page", "emitter": [Object], "eventsMap": [Map]}, "_context": {"_client": [CDPSession], "_contextId": 3, "_world": [DOMWorld]}, "_disposed": false, "_frameManager": {"_client": [CDPSession], "_contextIdToContext": [Map], "_frames": [Map], "_isolatedWorlds": [Set], "_mainFrame": [Frame], "_networkManager": [NetworkManager], "_page": [Page], "_timeoutSettings": [TimeoutSettings], "emitter": [Object], "eventsMap": [Map]}, "_page": {"_accessibility": [Accessibility], "_client": [CDPSession], "_closed": false, "_coverage": [Coverage], "_emulationManager": [EmulationManager], "_fileChooserInterceptors": [Set], "_frameManager": [FrameManager], "_javascriptEnabled": true, "_keyboard": [Keyboard], "_mouse": [Mouse], "_pageBindings": [Map], "_screenshotTaskQueue": [ScreenshotTaskQueue], "_target": [Target], "_timeoutSettings": [TimeoutSettings], "_touchscreen": [Touchscreen], "_tracing": [Tracing], "_viewport": [Object], "_workers": [Map], "emitter": [Object], "eventsMap": [Map]}, "_remoteObject": {"className": "HTMLCanvasElement", "description": "canvas#bg", "objectId": "{\"injectedScriptId\":3,\"id\":3}", "subtype": "node", "type": "object"}}

I've not found how to use this (with puppeteer) in the doc. Do you know the proper usage?

jest-dom v 4.2.4
puppeteer v 4.0.1


Solution

  • You do need the page.waitForSelector to wait for the element to be rendered, but you can assign the element to a variable with page.$ (it runs document.querySelector within the page) like this:

    await page.waitForSelector('#bg'); // puppeteer
    const bg = await page.$('#bg');
    

    But as it was suggested by others: it won't work together with @testing-library/jest-dom/extend-expect.

    With puppeteer you can check visibility like this:

    test('should check if element is visible', async function() {
        const isVisible = await page.evaluate(() => {
          const el = document.querySelector('my-selector');
          if (!el)
            return false;
          const style = window.getComputedStyle(el);
          return style && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
        });
        expect(isVisible).toBe(true);
      })
    

    [source of isVisible: Andrey Lushnikov, puppeteer GitHub]