Skip to content

Instantly share code, notes, and snippets.

@nishio
Created February 18, 2021 05:09
Show Gist options
  • Save nishio/06249db25dafef81646d961ec9c0c70e to your computer and use it in GitHub Desktop.
Save nishio/06249db25dafef81646d961ec9c0c70e to your computer and use it in GitHub Desktop.
import React, { Dispatch } from "react";
import { act, render, screen } from "@testing-library/react";
import { MyComponent } from "./MyComponent";
import { MyAsyncComponent, resolve, userTrigger } from "./MyAsyncComponent";
import { useState as originalUseState } from "react";
test("MyComponent1", () => {
type TSetState = React.Dispatch<React.SetStateAction<number>>;
let setValue: TSetState | undefined;
const exportSetValue = (s: TSetState) => {
setValue = s;
};
render(<MyComponent exportSetValue={exportSetValue} />);
expect(screen.getByText("0")).toBeTruthy();
expect(setValue).toBeTruthy();
act(() => {
setValue!(1);
});
expect(screen.queryByText("0")).toBeNull();
expect(screen.getByText("1")).toBeTruthy();
});
test("MyComponent2", async () => {
type TSetState = React.Dispatch<React.SetStateAction<number>>;
let setValue: TSetState | undefined;
const exportSetValue = (s: TSetState) => {
setValue = s;
};
const asyncUpdate: Promise<number> = new Promise((resolve) => {
resolve(1);
});
render(<MyComponent exportSetValue={exportSetValue} />);
expect(screen.getByText("0")).toBeTruthy();
expect(setValue).toBeTruthy();
console.log(1);
// act(() => {
// console.log(2);
// asyncUpdate.then((x) => {
// console.log(5);
// setValue!(x);
// });
// console.log(3);
// });
// console.log(4);
// expect(screen.queryByText("0")).toBeNull(); // fails
// expect(screen.getByText("1")).toBeTruthy();
});
test("MyComponent3", async () => {
let setValue: React.Dispatch<React.SetStateAction<number>> | undefined;
const exportSetValue = (s: React.Dispatch<React.SetStateAction<number>>) => {
setValue = s;
};
const asyncUpdate: Promise<number> = new Promise((resolve) => {
resolve(1);
});
render(<MyComponent exportSetValue={exportSetValue} />);
expect(screen.getByText("0")).toBeTruthy();
expect(setValue).toBeTruthy();
await asyncUpdate.then((x) => {
act(() => {
setValue!(x);
});
});
expect(screen.queryByText("0")).toBeNull(); // OK
expect(screen.getByText("1")).toBeTruthy();
});
test("MyComponent4", () => {
let setValue: React.Dispatch<React.SetStateAction<number>> | undefined;
const exportSetValue = (s: React.Dispatch<React.SetStateAction<number>>) => {
setValue = s;
};
const asyncUpdate: Promise<number> = new Promise((resolve) => {
resolve(1);
});
render(<MyComponent exportSetValue={exportSetValue} />);
expect(screen.getByText("0")).toBeTruthy();
expect(setValue).toBeTruthy();
return asyncUpdate
.then((x) => {
act(() => {
setValue!(x);
});
})
.then(() => {
expect(screen.queryByText("0")).toBeNull(); // OK
expect(screen.getByText("1")).toBeTruthy();
});
});
test("MyComponent5", async () => {
let setValue: React.Dispatch<React.SetStateAction<number>> | undefined;
const exportSetValue = (s: React.Dispatch<React.SetStateAction<number>>) => {
setValue = s;
};
const asyncUpdate: Promise<number> = new Promise((resolve) => {
resolve(1);
});
const userEventHandler = () => {
asyncUpdate.then((x) => {
setValue!(x);
});
};
render(<MyComponent exportSetValue={exportSetValue} />);
expect(screen.getByText("0")).toBeTruthy();
expect(setValue).toBeTruthy();
userEventHandler(); // Here
// expect(screen.queryByText("0")).toBeNull(); // fails
// expect(screen.getByText("1")).toBeTruthy();
});
test("MyAsyncComponent1", async () => {
jest.spyOn(React, "useState").mockImplementation((arg?: unknown): [
unknown,
Dispatch<unknown>
] => {
const [s, setS] = originalUseState(arg);
return [
s,
(arg: unknown) => {
act(() => {
setS(arg);
});
},
];
});
render(<MyAsyncComponent />);
expect(screen.getByText("0")).toBeTruthy();
console.log(3);
userTrigger();
console.log(5);
expect(screen.getByText("0")).toBeTruthy();
await resolve(1);
console.log(7);
expect(screen.queryByText("0")).toBeNull();
expect(screen.getByText("1")).toBeTruthy();
});
import { useState } from "react";
export type TUserTrigger = () => Promise<void>;
export type TResolve = (value: number) => void;
export let userTrigger: TUserTrigger;
export let resolve: TResolve;
export const MyAsyncComponent = () => {
const [value, setValue] = useState(0);
console.log(1);
userTrigger = () => {
console.log(4);
return new Promise<number>((res) => {
resolve = res;
}).then((x) => {
console.log(6);
setValue(x);
});
};
console.log(2);
return <span>{value}</span>;
};
import { useState } from "react";
export const MyComponent = (props: {
exportSetValue: (
setValue: React.Dispatch<React.SetStateAction<number>>
) => void;
}) => {
const [value, setValue] = useState(0);
props.exportSetValue(setValue);
return <span>{value}</span>;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment