Files
pezkuwi-apps/packages/test-support/src/utils/domAssertions.ts
T
Satoshi Qazi Muhammed 0c5b47ce0e Integration specs: node:test module mocks instead of jest.mock
The account, address, sidebar and bounties specs replaced hooks with
jest.mock, which the node:test runner does not have, so all five failed
to load and were excluded from yarn test. They now register mocks with
mock.module from node:test and import the page under test afterwards,
since Node only swaps a module that has not been loaded yet.

- test-support/mocks: mockPageHooks() replaces the hooks a Page reads.
  An ES module mock replaces every export, so each mock lists them all
  (useBestNumber's useBestNumberRelay included). The real useAccountInfo
  is wrapped, typed now, with the fixture identity merged in a typed
  helper.
- The page-specific mocks live with their page: useMultisigApprovals in
  page-accounts/test, useAddresses in page-addresses/test.
- jest-dom matchers were never registered for this runner; specs and
  page elements use assertHasClass, assertTextContent and assertVisible
  from test-support, with the same meaning.
- Page's mock api gains apiIdentity, which useAccountInfo reads.
- The bounties voting tooltip renders hidden and fades in, so the spec
  waits for it to become visible.
- jest/expect-expect counts the assert* helpers as assertions; the
  disable comments that only existed for that are removed.

Create and Bounties run green. Accounts, Addresses and Sidebar load and
stay skipped as upstream left them (their FIXMEs are about the reworked
tables). Needs @pezkuwi/dev 0.86.6 for the module mocks flag and the
fuller browser env.
2026-10-10 11:42:13 +04:00

56 lines
2.3 KiB
TypeScript

// Copyright 2017-2026 @pezkuwi/test-supports authors & contributors
// SPDX-License-Identifier: Apache-2.0
// DOM checks with the meaning of the matching @testing-library/jest-dom
// matchers, which the node:test based runner does not provide
import assert from 'node:assert/strict';
function describeElement (node: Node): string {
const html = (node as Partial<Element>).outerHTML ?? node.nodeName;
return html.length > 200
? `${html.slice(0, 200)}...`
: html;
}
/** As toHaveClass: the element carries the class */
export function assertHasClass (node: Node | null, className: string): void {
assert.ok(node, `Expected an element with class "${className}", found none`);
const classList = (node as Partial<Element>).classList;
assert.ok(classList, `Expected an element with class "${className}", found ${describeElement(node)}`);
assert.ok(classList.contains(className), `Expected class "${className}" on ${describeElement(node)}`);
}
/** As toHaveTextContent: the whitespace-normalized text contains the string, or matches the pattern */
export function assertTextContent (element: Node | null, expected: string | RegExp): void {
assert.ok(element, `Expected an element with text ${String(expected)}, found none`);
const text = (element.textContent ?? '').replace(/\s+/g, ' ').trim();
if (typeof expected === 'string') {
assert.ok(text.includes(expected), `Expected text containing "${expected}", found "${text}"`);
} else {
assert.match(text, expected);
}
}
/** As toBeVisible: in the document, and neither it nor an ancestor is hidden */
export function assertVisible (element: Element | null): void {
assert.ok(element, 'Expected a visible element, found none');
assert.ok(element.isConnected, `Expected ${describeElement(element)} to be in the document`);
for (let current: Element | null = element; current; current = current.parentElement) {
const style = current.ownerDocument.defaultView?.getComputedStyle(current);
const isHidden = current.hasAttribute('hidden') ||
style?.display === 'none' ||
style?.visibility === 'hidden' ||
style?.visibility === 'collapse' ||
style?.opacity === '0';
assert.ok(!isHidden, `Expected ${describeElement(element)} to be visible, hidden by ${describeElement(current)}`);
}
}