Skip to content

Instantly share code, notes, and snippets.

@deanrad
Created July 19, 2021 15:02
Show Gist options
  • Save deanrad/741b55b9cdf97e08401420dd8fbb7e68 to your computer and use it in GitHub Desktop.
Save deanrad/741b55b9cdf97e08401420dd8fbb7e68 to your computer and use it in GitHub Desktop.
import React from 'react'
import "@testing-library/jest-dom";
import { renderHook, act } from "@testing-library/react-hooks";
import { render, fireEvent } from "@testing-library/react";
import { useCounterLogic } from './examples/useCounterLogic';
import { CounterHook } from './examples/CounterHook'
describe.only('CounterLogic', () => {
describe('increment', () => {
it('should change count by 1', () => {
const { result } = renderHook(() =>
useCounterLogic()
);
expect(result.current.count).toEqual(0)
act(() => {
result.current.inc();
})
expect(result.current.count).toEqual(1)
})
xit('should be a stable reference', () => {
const { result } = renderHook(() =>
useCounterLogic()
);
// const { result : nextRender } = renderHook(() =>
// useCounterLogic()
// );
// expect(result.current.inc).toEqual(nextRender.current.inc)
expect(result.current.inc).toBe(()=>null)
})
describe('when rendered into a component', () => {
it('changes it', () => {
const { queryByTestId: query } = render(
<CounterHook />
);
expect(query("hook-count")).toHaveTextContent("0");
fireEvent.click(query("hook-button"));
expect(query("hook-count")).toHaveTextContent("1");
})
})
})
})
import React, { useState } from "react";
import { CounterLogic, useCounterLogic } from "./useCounterLogic";
// Because hook/UI intermingling - challenging to render in Storybook
// export const CounterHook = ({ id = "hook" }) => {
// const {count, inc} = useCounterLogic();
// return (
// <section>
// <output data-testid="hook-count">{count}</output>
// <button
// data-testid="hook-button"
// onClick={inc}
// >
// Count
// </button>
// </section>
// );
// };
// Separate UI, depends only on the interface of the hook, not its implementation
const CounterUI = (props: CounterLogic) => {
const { count, inc } = props;
return (
<section>
<output data-testid="hook-count">{count}</output>
<button
data-testid="hook-button"
onClick={inc}
>
Count
</button>
</section>
);
};
// Use a generic HOC wrapper to bind them together. TODO - name the component
const withHook = hook => component => function () {
const result = hook();
return React.createElement(component, result)
}
export const CounterHook = withHook(useCounterLogic)(CounterUI);
import { useMemo, useState } from 'react'
export interface CounterLogic {
inc: () => void;
count: number;
}
export function useCounterLogic(): CounterLogic {
const [count, setCount] = useState(0);
const inc = useMemo(() => () => setCount(c => c+1), [])
return { inc, count }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment