From 5054b5c72d4a48f0ff8661bca84929d3e8bfc0ff Mon Sep 17 00:00:00 2001 From: keiya sasaki <34934510+keiya01@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:25:34 +0900 Subject: [PATCH] fix: strict mode (#668) * fix: strict mode * test --- src/Camera/Camera.stories.tsx | 15 +++ src/Entity/Entity.stories.tsx | 220 +++++++++++++++++++++++++++++++++- src/Entity/Entity.test.tsx | 10 +- src/core/component.test.tsx | 72 ++++++----- src/core/hooks.ts | 12 +- 5 files changed, 295 insertions(+), 34 deletions(-) diff --git a/src/Camera/Camera.stories.tsx b/src/Camera/Camera.stories.tsx index e7c048a9a..e6cab70c1 100644 --- a/src/Camera/Camera.stories.tsx +++ b/src/Camera/Camera.stories.tsx @@ -1,6 +1,7 @@ import { actions } from "@storybook/addon-actions"; import { Meta, StoryObj } from "@storybook/react"; import { Cartesian3 } from "cesium"; +import { StrictMode } from "react"; import CameraFlyTo from "../CameraFlyTo"; import Viewer from "../Viewer"; @@ -22,3 +23,17 @@ export const Basic: Story = { ), }; + +export const Strict: Story = { + render: args => ( + + + + + + + ), +}; diff --git a/src/Entity/Entity.stories.tsx b/src/Entity/Entity.stories.tsx index 0040c9c94..c31f0e1fe 100644 --- a/src/Entity/Entity.stories.tsx +++ b/src/Entity/Entity.stories.tsx @@ -11,7 +11,7 @@ import { // Rectangle, // Math as CesiumMath, } from "cesium"; -import { useState, useEffect, useRef, useMemo, FC } from "react"; +import { useState, useEffect, useRef, useMemo, FC, StrictMode } from "react"; import BillboardGraphics from "../BillboardGraphics"; import BoxGraphics from "../BoxGraphics"; @@ -391,3 +391,221 @@ export const Graphics: Story = { ), }; + +export const Strict: Story = { + render: args => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* + + */} + {/* + + */} + {/* + + */} + + + ), +}; diff --git a/src/Entity/Entity.test.tsx b/src/Entity/Entity.test.tsx index 9cf5dad52..b586d2a9e 100644 --- a/src/Entity/Entity.test.tsx +++ b/src/Entity/Entity.test.tsx @@ -37,10 +37,12 @@ it("should mount", async () => { , ); - expect(ctx.entityCollection?.add).toBeCalledWith(expect.any(CesiumEntity)); - expect(ref.current?.cesiumElement).toBeInstanceOf(CesiumEntity); - expect(ref.current?.cesiumElement?.name).toBe("test"); - expect(ref.current?.cesiumElement?.definitionChanged.numberOfListeners).toBe(1); + await waitFor(() => { + expect(ctx.entityCollection?.add).toBeCalledWith(expect.any(CesiumEntity)); + expect(ref.current?.cesiumElement).toBeInstanceOf(CesiumEntity); + expect(ref.current?.cesiumElement?.name).toBe("test"); + expect(ref.current?.cesiumElement?.definitionChanged.numberOfListeners).toBe(1); + }); }); it("should unmount", () => { diff --git a/src/core/component.test.tsx b/src/core/component.test.tsx index c57d23258..3ce12c352 100644 --- a/src/core/component.test.tsx +++ b/src/core/component.test.tsx @@ -11,7 +11,7 @@ beforeEach(() => { }); describe("core/component", () => { - it("should create and expose cesium element correctly on initialized", () => { + it("should create and expose cesium element correctly on initialized", async () => { const create = vi.fn(() => "foobar"); const value = { hoge: 1 } as any; @@ -28,9 +28,11 @@ describe("core/component", () => { , ); - expect(create).toBeCalledWith(value, { test: 1 }, null); - expect(create).toBeCalledTimes(1); - expect(ref.current?.cesiumElement).toBe("foobar"); + await waitFor(() => { + expect(create).toBeCalledWith(value, { test: 1 }, null); + expect(create).toBeCalledTimes(1); + expect(ref.current?.cesiumElement).toBe("foobar"); + }); }); it("should create and expose cesium element correctly on initialized asynchronously", async () => { @@ -80,7 +82,7 @@ describe("core/component", () => { }); }); - it("should set cesium events after created", () => { + it("should set cesium events after created", async () => { const cesiumElement = { hoge: new Event(), }; @@ -93,10 +95,12 @@ describe("core/component", () => { render( {}} />); - expect(cesiumElement.hoge.numberOfListeners).toBe(1); + await waitFor(() => { + expect(cesiumElement.hoge.numberOfListeners).toBe(1); + }); }); - it("should set cesium props after created", () => { + it("should set cesium props after created", async () => { const cesiumElement = { foo: 0, }; @@ -110,7 +114,9 @@ describe("core/component", () => { render(); - expect(cesiumElement.foo).toBe(10); + await waitFor(() => { + expect(cesiumElement.foo).toBe(10); + }); }); it("should update cesium props", async () => { @@ -159,9 +165,11 @@ describe("core/component", () => { const { rerender } = render( {}} hoge={() => {}} />); - expect(cesiumElement.foo.numberOfListeners).toBe(1); - expect(cesiumElement.bar.numberOfListeners).toBe(0); - expect(cesiumElement.hoge.numberOfListeners).toBe(1); + await waitFor(() => { + expect(cesiumElement.foo.numberOfListeners).toBe(1); + expect(cesiumElement.bar.numberOfListeners).toBe(0); + expect(cesiumElement.hoge.numberOfListeners).toBe(1); + }); rerender( {}} hoge={() => {}} />); @@ -220,7 +228,9 @@ describe("core/component", () => { const { rerender } = render(); - expect(updateFn).toBeCalledTimes(0); + await waitFor(() => { + expect(updateFn).toBeCalledTimes(0); + }); rerender(); @@ -230,7 +240,7 @@ describe("core/component", () => { }); }); - it("should provide context", () => { + it("should provide context", async () => { const create1 = vi.fn(() => "test"); const create2 = vi.fn(() => "test"); @@ -253,8 +263,10 @@ describe("core/component", () => { , ); - expect(create1).toBeCalledWith({ context: "a", context2: "foo" }, expect.anything(), null); - expect(create2).toBeCalledWith({ context: "b", context2: "foo" }, expect.anything(), null); + await waitFor(() => { + expect(create1).toBeCalledWith({ context: "a", context2: "foo" }, expect.anything(), null); + expect(create2).toBeCalledWith({ context: "b", context2: "foo" }, expect.anything(), null); + }); }); it("should invoke onUpdate event when being dirty", () => { @@ -300,7 +312,7 @@ describe("core/component", () => { }); }); - it("should render container", () => { + it("should render container", async () => { const createFn = vi.fn(() => "foobar"); const Component = createCesiumComponent({ @@ -316,14 +328,16 @@ describe("core/component", () => { , ); - expect(createFn).toBeCalledWith( - expect.anything(), - expect.anything(), - expect.any(HTMLDivElement), - ); - const containers = screen.getAllByTestId("resium-container"); - expect(containers.length).toBe(1); - expect(containers[0].getAttribute("class")).toBe("hoge"); + await waitFor(() => { + expect(createFn).toBeCalledWith( + expect.anything(), + expect.anything(), + expect.any(HTMLDivElement), + ); + const containers = screen.getAllByTestId("resium-container"); + expect(containers.length).toBe(1); + expect(containers[0].getAttribute("class")).toBe("hoge"); + }); }); it("should keep state", () => { @@ -356,7 +370,7 @@ describe("core/component", () => { }); }); - it("should not render when noChildren is true", () => { + it("should not render when noChildren is true", async () => { const Component = createCesiumComponent({ name: "test", noChildren: false, @@ -368,7 +382,9 @@ describe("core/component", () => { , ); - expect(screen.getByTestId("hello")).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByTestId("hello")).toBeInTheDocument(); + }); const Component2 = createCesiumComponent({ name: "test", @@ -381,6 +397,8 @@ describe("core/component", () => { , ); - expect(screen.queryByTestId("hello")).not.toBeInTheDocument(); + await waitFor(() => { + expect(screen.queryByTestId("hello")).not.toBeInTheDocument(); + }); }); }); diff --git a/src/core/hooks.ts b/src/core/hooks.ts index c74db0c38..c6881bbd6 100644 --- a/src/core/hooks.ts +++ b/src/core/hooks.ts @@ -163,6 +163,9 @@ export const useCesiumComponent = { + // Wait one tick to resolve Cesium's unmount process. + await new Promise(r => queueMicrotask(() => r(undefined))); + // Initialize cesium element const maybePromise = create?.(ctx, initialProps.current, wrapperRef.current); @@ -219,6 +222,9 @@ export const useCesiumComponent = { + // Wait one tick to resolve Cesium's unmount process. + await new Promise(r => queueMicrotask(() => r(undefined))); + // Wait mount before unmount if (mountReadyRef.current) { await mountReadyRef.current; @@ -250,7 +256,6 @@ export const useCesiumComponent = { + // Need to update this state before Cesium is updated, + // because Viewer's children must be hidden before it's unmounted. + setMounted(false); unmountReadyRef.current = unmount(); }; - }, []); // eslint-disable-line react-hooks/exhaustive-deps + }, [mount, unmount]); // Update properties of cesium element useEffect(() => {