Skip to content

[Feature]: Add toBeReactivePure matcher #3064

Open
@MillerSvt

Description

@MillerSvt

🚀 Feature Proposal

Sometimes, when working with functions that use signals, we need to ensure that our function is reactive pure. This means that if any methods or effects call this function, it should not have any side effects based on the signal. To achieve this, I propose adding a special matcher, such as the toThrow matcher.

Motivation

I believe that having the option to check for reactive purity could help Angular developers become more responsible when working with reactive functions.

Possible solution

declare global {
	namespace jest {
		interface Matchers<R> {
			toBeReactivePure: () => R;
		}
	}
}

expect.extend({
	toBeReactivePure: function (
		this: jest.MatcherContext,
		fn: () => void,
	): jest.CustomMatcherResult {
		const reactiveNode: ReactiveNode = Object.create(REACTIVE_NODE);
		const prevConsumer = setActiveConsumer(reactiveNode);

		reactiveNode.consumerAllowSignalWrites = true;

		try {
			fn();
		} finally {
			setActiveConsumer(prevConsumer);
		}

		if (reactiveNode.producerNode?.length) {
			return {
				message: () =>
					`Expected to be reactive pure: Found ${reactiveNode.producerNode?.length} producers`,
				pass: false,
			};
		}

		return {
			message: () => `Expected to be not reactive pure`,
			pass: true,
		};
	},
});

Usage

it('should not register producers on consumer in reactive context when updating signal', () => {
	const customSignal = customSignal('');

	expect(() => {
		customSignal.set(newValue1);
		customSignal.update(() => newValue2);
	}).toBeReactivePure();
});

Real world example: ngxtension/ngxtension-platform#593

Additional

I can create pr with that

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions