0

I have the following set up:

  • E2E Test Utils - standard WP Gutenberg e2e testing set that uses Jest and Puppeteer
  • testing-library/pptr-testing-library - All your favorite user-centric querying functions from @testing-library/react & @testing-library/library available from Puppeteer!

I'm having a problem testing for appearance and disappearance of elements in the GB editor. I'm now aware that extended assertions don't work with Puppeteer. I just can't figure out what to test for. When I run the test in an interactive mode, I can see that everything is going fine, but I don't get the correct result. The result of the query is just an empty object. Here's a snippet of my code:

import {
    enablePageDialogAccept,
    setBrowserViewport,
    createNewPost,
    openDocumentSettingsSidebar,
    insertBlock,
    loginUser,
} from '@wordpress/e2e-test-utils';

import '@testing-library/jest-dom/extend-expect';
import { getDocument, queries, waitFor } from 'pptr-testing-library';

import { clearPuppeteerBrowser } from '../../../lib/helpers/e2eHelpers';

const {
    getByRole,
    getByLabelText,
    getByDisplayValue,
    getByText,
    queryByLabelText,
    findByRole,
    findByLabelText,
    findByText,
    findAllByText,
} = queries;

describe('CVGB Button block', () => {
  // Initialize vars within suite's scope
  let $document;
  let $editorSettings;
  let $editorContent;

  // Enable page dialog before running any tests
  beforeAll(async () => {
    await clearPuppeteerBrowser();
    await loginUser();
    await enablePageDialogAccept();
  });

  // Wait for creating a new post before running each of the tests
  beforeEach(async () => {
    await createNewPost();
    $document = await getDocument(page);

    // we want to look for Sidebar region only
    $editorSettings = await getByRole($document, 'region', { name: 'Editor settings' });

    // the same for the editor content, so we don't get repeated components from all the document
    $editorContent = await getByRole($document, 'region', { name: 'Editor content' });
  });

  it('should be able to unset a Link when URL is already set', async () => {
    await insertBlock('CVGB Button');
    await openDocumentSettingsSidebar();

    const $linkButton = await findByRole($document, 'button', {
      name: 'Link',
    });
    await $linkButton.click();

    const $URLInput = await findByRole($document, 'combobox', {
      name: 'URL',
    });
    await $URLInput.click();
    await $URLInput.type('https://www.google.es');
    await $URLInput.press('Enter');

    await waitFor(() => {
      expect(
        findByLabelText($document, 'Currently selected', {
          exact: false,
        })
      ).toBeInTheDocument();
    });
  });
});

Here is the error I see:

Result of the test above

The complete Node error message below the test reads:

(node:41767) UnhandledPromiseRejectionWarning: Error: Protocol error (Runtime.callFunctionOn): Target closed.
    at /Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:208:63
    at new Promise (<anonymous>)
    at CDPSession.send (/Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/puppeteer-core/lib/cjs/puppeteer/common/Connection.js:207:16)
    at ExecutionContext._evaluateInternal (/Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/puppeteer-core/lib/cjs/puppeteer/common/ExecutionContext.js:200:50)
    at ExecutionContext.evaluateHandle (/Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/puppeteer-core/lib/cjs/puppeteer/common/ExecutionContext.js:151:21)
    at /Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/pptr-testing-library/lib/index.ts:101:8
    at Generator.next (<anonymous>)
    at /Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/pptr-testing-library/dist/index.js:8:71
    at new Promise (<anonymous>)
    at Object.<anonymous>.__awaiter (/Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/node_modules/pptr-testing-library/dist/index.js:4:12)
(node:41767) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 908)

EDIT: In response to Caleb Eby's asnwer

I thought that's what the waitFor() is for… however if I add only the await findByLabelText(), I get an error:

SyntaxError: /Users/my-user/gb-siteapp/public/wp-content/plugins/cv-wp-gb-lib-blocks/blocks/button/test/buttonBlock.e2e.spec.js: Unexpected reserved word 'await'. (126:16)

If I change it to:

        await waitFor(async () => {
            expect(
                await findByLabelText($document, 'Currently selected', {
                    exact: false,
                })
            ).toBeInTheDocument();
        });

It takes a very long time to run the test and ends in error:

    expect(received).toBeInTheDocument()

    received value must be an HTMLElement or an SVGElement.
    Received has type:  object
    Received has value: 
    {
        "_client": {
            "_callbacks": [Map],
            "_connection": [Connection],
            "_sessionId": "9E13F5776A59D1DD6A177F48A9D1A543",
            "_targetType": "page",
            "emitter": [Object],
            "eventsMap": [Map]
        },
        "_context": {
            "_client": [CDPSession],
            "_contextId": 17,
            "_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": "HTMLDivElement",
            "description": "div.block-editor-link-control__search-item.is-current",
            "objectId": "-193265238525024879.17.113",
            "subtype": "node",
            "type": "object"
        }
    }

This actually has a possible culprit of a solution, but what is the right way of testing for this (instead of toBeInTheDocument())?

crs1138
  • 926
  • 1
  • 12
  • 23
  • It turns out that pptr-testing-library can't use the `expect` assertion extensions such as `.toBeInTheDocument()`. My question stands, how do I assert the element returned by a `findBy*()` query is the one I'm expecting it to be? Source: https://testing-library.com/docs/pptr-testing-library/intro/#known-limitations – crs1138 Dec 03 '21 at 12:01

1 Answers1

2

It looks like you are missing an await inside of the expect block, since findByLabelText returns a promise:

      expect(
        await findByLabelText($document, 'Currently selected', {
          exact: false,
        })
      ).toBeInTheDocument();

Caleb Eby
  • 356
  • 3
  • 14
  • I've edited the question in reaction to your suggestion. How could I be certain that the return object represents an element with label `Currently selected`? – crs1138 Jul 22 '21 at 06:38
  • @crs1138 did you find any solution? I'm facing with the same error – Manspof Sep 15 '22 at 14:29
  • @Manspof unfortunately, I haven't been able to solve this yet. The e2e tests remain flaky and our PO decided not to spend anymore time on them => we stopped using them. – crs1138 Dec 27 '22 at 07:53