Skip to content

Instantly share code, notes, and snippets.

@Dobby89
Last active September 3, 2025 12:20
Show Gist options
  • Select an option

  • Save Dobby89/0cb28497440aead3ffa03aea231439df to your computer and use it in GitHub Desktop.

Select an option

Save Dobby89/0cb28497440aead3ffa03aea231439df to your computer and use it in GitHub Desktop.
Vitest / Jest / React Testing Library

Only run tests against files which have been changed (--passWithNoTests used in case no tested files have changed)

jest --onlyChanged --passWithNoTests

SELF_SIGNED_CERT_IN_CHAIN - Error: self-signed certificate in certificate chain

If you an error like below when trying to run a command, you can prefix the command with export NODE_TLS_REJECT_UNAUTHORIZED=0 && (as per below).

Error: self-signed certificate in certificate chain
    at TLSSocket.onConnectSecure (node:_tls_wrap:1677:34)
    at TLSSocket.emit (node:events:519:28)
    at TLSSocket._finishInit (node:_tls_wrap:1076:8)
    at ssl.onhandshakedone (node:_tls_wrap:862:12) {
code: 'SELF_SIGNED_CERT_IN_CHAIN' }

export NODE_TLS_REJECT_UNAUTHORIZED=0 && <command you want to run>

Mock React.useId for snapshots

If you use React.useId in your components then it might break some snapshots as it will generate a random ID every time.

Based on https://stackoverflow.com/a/79539013/5243574

// setTests.ts

beforeEach(() => {
	vi.mock('react', async (importOriginal) => ({
		// Mock useId from react so that snapshots are stable
		...(await importOriginal<typeof import('react')>()),
		useId: () => 1,
	}));
});

Using React Hook Form with useFakeTimers

You must ensure you set vi.useFakeTimers({ shouldAdvanceTime: true }); otherwise validation does not get triggered.

// Component file
// --------------

import { render, screen, waitFor } from '@testing-library/react';

import SimpleForm from './SimpleForm';
import userEvent from '@testing-library/user-event';

describe('SimpleForm default journey', () => {
	const user = userEvent.setup();

	beforeEach(() => {
		vi.useFakeTimers({ shouldAdvanceTime: true });
	});

	afterAll(() => {
		vi.useRealTimers();
	});

	it('should validate the form', async () => {
		render(<SimpleForm />);

		expect(screen.getByText('Name')).toBeInTheDocument();

		await user.click(screen.getByRole('button', { name: 'Submit' }));

		await waitFor(() => {
			expect(screen.getByText('Name is required.')).toBeInTheDocument();
		});
	});
});

// Test file
// --------------

import { render, screen, waitFor } from '@testing-library/react';

import SimpleForm from './SimpleForm';
import userEvent from '@testing-library/user-event';

describe('SimpleForm default journey', () => {
	const user = userEvent.setup();

	beforeEach(() => {
		vi.useFakeTimers({ shouldAdvanceTime: true });
	});

	afterAll(() => {
		vi.useRealTimers();
	});

	it('should validate and submit the name', async () => {
		render(<SimpleForm />);

		expect(screen.getByText('Name')).toBeInTheDocument();

		await user.click(screen.getByRole('button', { name: 'Submit' }));

		await waitFor(() => {
			expect(screen.getByText('Name is required.')).toBeInTheDocument();
		});
	});
});

Text content matcher

Taken from testing-library/dom-testing-library#410 (comment)

/**
 * Getting the deepest element that contain string / match regex even when it split between multiple elements
 *
 * @example
 * For:
 * <div>
 *   <span>Hello</span><span> World</span>
 * </div>
 *
 * screen.getByText('Hello World') // ❌ Fail
 * screen.getByText(textContentMatcher('Hello World')) // ✅ pass
 */
function textContentMatcher(textMatch: string | RegExp) {
  const hasText = (typeof textMatch === 'string')
    ? (node: Element) => node.textContent === textMatch
    : (node: Element) => textMatch.test(node.textContent);

  return (_content: string, node: Element) => {
    if (!hasText(node)) {
      return false;
    }
    
    const childrenDontHaveText = Array.from(node?.children || []).every((child) => !hasText(child));

    return childrenDontHaveText
  };
}
/**
 * Creates a custom matcher function to check if an element's textContent
 * matches a given string exactly or a given regular expression.
 * @param matcher The string or RegExp to match against the element's textContent.
 * @returns A MatcherFunction compatible with React Testing Library queries.
 */
export const toHaveTextContent = (
	matcher: string | RegExp,
): MatcherFunction => {
	return (_content, element) => {
		// Ensure element is not null and has textContent property
		if (!element || typeof element.textContent !== 'string') {
			return false;
		}

		const elementText = element.textContent;

		if (typeof matcher === 'string') {
			// If matcher is a string, perform an exact match
			return elementText === matcher;
		} else if (matcher instanceof RegExp) {
			// If matcher is a RegExp, test against it
			return matcher.test(elementText);
		}

		// Fallback for unexpected matcher types (though TypeScript helps prevent this)
		return false;
	};
};

Partial text match

When you want to find some text within a string of text, you may get the following error

TestingLibraryElementError: Unable to find an element with the text: string to find. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

Instead, you can convert the string you want to find into a regex expression and find it that way.

import React from 'react';

import { render, screen } from '@testing-library/react';

function escapeRegExp(stringToGoIntoTheRegex: string) {
	return stringToGoIntoTheRegex.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

test('find text', () => {
	render(<div>This is a sentence with a string to find</div>);

	// This will work
	expect(screen.getByText('This is a sentence with a string to find')).toBeInTheDocument();

	// This will work
	expect(screen.getByText(new RegExp(escapeRegExp('string to find'), 'g'))).toBeInTheDocument();

	// This will NOT work
	expect(screen.getByText('string to find')).toBeInTheDocument();
});

Mock useLocation from React Router

Yoinked from https://stackoverflow.com/a/74820547/5243574

import React from 'react';
import ExampleComponent from './ExampleComponent';
import { fireEvent, render } from '@testing-library/react';
import { MemoryRouter} from 'react-router-dom';
import { shallow } from 'enzyme';

const renderComponent = () => {
  return (
      <MemoryRouter
          initialEntries={["/one", "/two", { pathname: 'https://URL/' }]}
          initialIndex={1}>
         <ExampleComponent />
     </MemoryRouter>
   );
}

describe('<ExampleComponent />', () => {
  it('should render correctly', () => {
    shallow(renderComponent());
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment