Skip to content

paullewisn/jest-snapshot-propifier

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

42 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

jest-snapshot-propifier

Reduce the size of snapshots while also encouraging atomic testing practices.

createMock

returns: jest.Mock

Props and children are represented in a uniform and logical way. Props which require further testing are highlighted within the snapshot. Components are replaced with either divs or spans which have data-attributes set as the props which have been passed in.

Setup (div)

/Bar/__mocks__/index.ts

import { createMock } from "jest-snapshot-propifier";

export const Foo = createMock({ name: "Bar" });

/Foo/index.ts

export const Foo = (props) => <Bar {...props} />;

/Foo/spec.tsx

With no props

test("With no props", () => {
	expect(snapshotOf(<Foo />)).toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	      />
        `);
});

With basic props

test("With basic props", () => {
	expect(snapshotOf(<Foo string="string" number={42} />))
		.toMatchInlineSnapshot(`
    	        <div
    	          data-component="<Bar />"
    	          data-number={42}
    	          data-string="string"
    	        />
        `);
});

With objects as props

test("With objects as props", () => {
	const muchWow = {
		string: "string",
		number: 42,
		object: { much: "wow" },
	};

	expect(snapshotOf(<Foo object={muchWow} />)).toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	        data-object="{\\"string\\":\\"string\\",\\"number\\":42,\\"object\\":{\\"much\\":\\"wow\\"}}"
    	      />
        `);
});

With functions as props

    test("With functions as props", () => {
    	expect(snapshotOf(<Foo function={() => "function"} />))
    		.toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	        data-function="[! Function to test !]"
    	      />
        `);
    	const mockedBar = Bar as jest.Mock;

    	const [[barProps]] = mockedBar.mock.calls;

    	expect(barProps.function()).toBe("function");
    });

With components as props

    test("With components as props", () => {
    	const InnerFoo = createMock({ name: "InnerFoo" });

    	expect(snapshotOf(<Foo weirdFlex={<InnerFoo />} />))
    		.toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	        data-weird_flex="[! Component to test !]"
    	      />
        `);

    	const mockedBar = Bar as jest.Mock;

    	const [[barProps]] = mockedBar.mock.calls;
    	const WeirdFlex = () => barProps.weirdFlex;

    	expect(snapshotOf(<WeirdFlex />)).toMatchInlineSnapshot(`
            <div
            data-component="<InnerFoo />"
            />
        `);
    });

With basic children

test("With basic children", () => {
	expect(snapshotOf(<Foo>children</Foo>)).toMatchInlineSnapshot(`
    	          <div
    	            data-component="<Bar />"
    	          >
    	            children
    	          </div>
        `);
});

With components as children

test("With components as children", () => {
	const InnerFoo = () => <>InnerFoo</>;

	expect(
		snapshotOf(
			<Foo>
				<InnerFoo />
			</Foo>
		)
	).toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	      >
    	        InnerFoo
    	      </div>
        `);
});

Setup (span)

For cases where it would not be appropriate to use a div

/Bar/__mocks__/index.ts

import { createMock } from "jest-snapshot-propifier";

export const Foo = createMock({ name: "Bar", element: "span" });

/Foo/index.ts

export const Foo = (props) => <Bar {...props} />;

/Foo/spec.tsx

test("With no props", () => {
	expect(snapshotOf(<Foo />)).toMatchInlineSnapshot(`
    	      <span
    	        data-component="<Bar />"
    	      />
        `);
});

snapshotOf

returns: ReactTestRendererJSON | ReactTestRendererJSON[]

Convenience wrapper for react-test-renderer's snapshot generator

Basic use case

/Foo/index.ts

export const Foo = (props) => <Bar {...props} />;

/Foo/spec.tsx

test("With no props", () => {
	expect(snapshotOf(<Foo />)).toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	      />
        `);
});

With useEffect

/Foo/index.ts

export const Foo = ({ extraFoo, ...props }) => {
	const [extraBar, setExtraBar] = useState();

	useEffect(() => {
		setExtraBar(extraFoo);
	}, [extraFoo]);

	return <Bar {...props} extraBar={extraBar} />;
};

Passing { flushEffects: true } will allow useEffect to complete before creating the snapshot:

/Foo/spec.tsx

test("With flushEffects", () => {
	expect(snapshotOf(<Foo extraFoo="πŸ“" />), { flushEffects: true })
		.toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
				data-extra-foo="πŸ“"
    	      />
        `);
});

...compared to { flushEffects: false }:

/Foo/spec.tsx

test("Without flushEffects", () => {
	expect(snapshotOf(<Foo extraFoo="πŸ“" />, { flushEffects: false }))
		.toMatchInlineSnapshot(`
    	      <div
    	        data-component="<Bar />"
    	      />
        `);
});

create

returns ReactTestRenderer

Convenience wrapper for react-test-renderer's renderer. Options as snapshotOf. Useful if there is a requirement to cause rerenders but need to ensure effects have been flushed on the original call.

Basic use case

/Foo/spec.tsx

test("With create", () => {
	const foo = create(<Foo extraFoo="πŸ₯" />, { flushEffects: true });

	expect(Foo).toHaveBeenCalledTimes(1);
	expect(Foo).toHaveBeenCalledWith("πŸ₯");

	act(() => {
		foo.update(<Foo extraFoo="πŸ‰" />);
	});

	expect(Foo).toHaveBeenCalledTimes(2);
	expect(Foo).toHaveBeenCalledWith("πŸ‰");

	//or use foo.toJSON() if you just want a snapshot
});

If you've found this useful I'd appreciate a beer 🍺

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published