【问题标题】:"Nothing was returned from render" NextJS & Apollo + Jest“渲染没有返回任何内容” NextJS & Apollo + Jest
【发布时间】:2021-10-14 12:55:46
【问题描述】:

我有一个玩笑的测试配置,我正试图用它来测试用 NextJS 的 apollo 客户端 HOC 包装器包装的 NextJS 页面,我当前的配置产生了这个错误:

对于这个堆栈的各种在线配置,我如何正确设置 Jest 测试似乎还不清楚。

App.tsx 文件:

import React from "react";
import theme from "../styles/theme";

import { ChakraProvider } from "@chakra-ui/react";
import { AppProps } from "next/app";
import { msalConfig } from "../utils/ms-graph/config";
import { PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";
import withApollo from "../utils/withApollo";
const msalInstance = new PublicClientApplication(msalConfig);

function MyApp({ Component, pageProps }: AppProps & any) {
  return (
    <MsalProvider instance={msalInstance}>
      <ChakraProvider resetCSS theme={theme}>
        <Component {...pageProps} />
      </ChakraProvider>
    </MsalProvider>
  );
}

export default withApollo({ ssr: true })(MyApp);

Jest 文件:

配置文件jest.config.ts

import type { Config } from "@jest/types";

export default async (): Promise<Config.InitialOptions> => {
  return {
    collectCoverage: false,
    globals: {
      "ts-jest": {
        tsconfig: "./tsconfig.test.json",
      },
    },
    moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
    preset: "ts-jest",
    testEnvironment: "jsdom",
    testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
    testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|js?|tsx?|ts?)$",
    transform: {
      "^.+\\.(ts|tsx)?$": "ts-jest",
      "^.+\\.(js|jsx|tsx)$": "babel-jest",
      "^.+\\.svg$": "<rootDir>/svgTransform.js",
    },
    transformIgnorePatterns: [
      "[/\\\\]node_modules[/\\\\](?!lodash-es/).+\\.js$",
    ],
  };
};

实用程序文件test-utils.tsx

import React from 'react';
import { render } from '@testing-library/react';
import { ChakraProvider as ThemeProvider } from '@chakra-ui/react';

const ChakraRenderer: React.FC = ({ children }: React.PropsWithChildren<Record<string, any>>) => {
  return <ThemeProvider>{children}</ThemeProvider>;
};

const customRender = (ui: any, options = {}) =>
  render(ui, {
    wrapper: ChakraRenderer,
    ...options,
  });

export * from '@testing-library/react';
export { customRender as render };

实用程序文件test-utils.tsx

import { render } from "../test-utils";
import Index from "../../pages/index";

test("NavBar should detect guest users button by text.", () => {
  const { getByText } = render(<Index />, {});

  const azureSignInBtn = getByText("Azure Login");
  console.log("azureSignInBtn", !!azureSignInBtn);
});

withApollo.ts 文件:

import { withApollo } from "next-apollo";
import { ApolloClient, HttpLink, InMemoryCache } from "@apollo/client";
import { NextPageContext } from "next";
import { BE_URL, __prod__ } from "./constants";

const createClient: any = (
  initialState: any,
  ctx: NextPageContext | undefined
) => {
  return new ApolloClient({
    uri: <string>BE_URL,
    link: new HttpLink({
      credentials: "include",
      uri: <string>BE_URL,
    }),
    headers: {
      cookie:
        (typeof window === "undefined"
          ? ctx?.req?.headers.cookie
          : undefined) || "",
    },
    cache: <{} | any>new InMemoryCache({
      typePolicies: {
        Query: {},
      },
    }).restore(initialState),
    credentials: "include",
  });
};

export default withApollo(createClient) as any;

NextJS 页面文件:

实用文件index.tsx

import React from "react";
import { Layout } from "../components/Layout";
import { SimpleCTA } from "../components/cta/SimpleCTA";

const Index = () => {
  return (
    <Layout>
      <SimpleCTA />
    </Layout>
  );
};

export default Index;

组件文件:

实用文件Layout.tsx

import React from "react";
import { Wrapper, WrapperVariant } from "./Wrapper";
import { NavBar } from "./NavBar";
import { useIsUserQuery, User } from "../generated/graphql";
import { useRouter } from "next/router";
import { useIsAuthenticated } from "@azure/msal-react";

interface LayoutProps {
  variant?: WrapperVariant;
  bg?: string;
  height?: string | number;
  width?: string | number;
}

export const Layout: React.FC<LayoutProps> = ({
  bg,
  height,
  width,
  children,
  variant,
}) => {
  const { data: { isUser } = {}, loading } = useIsUserQuery({ ssr: false });
  const isAuthenticated = useIsAuthenticated();
  const user: User & any = isUser?.user;
  const router = useRouter();

  const wrapperContent = (
    <Wrapper height={height} width={width} bg={bg} variant={variant}>
      {children}
    </Wrapper>
  );

  const baseNav = (
    <>
      {router.pathname === "/profile" && isAuthenticated ? (
        <div>null</div>
      ) : (
        <NavBar />
      )}
      {wrapperContent}
    </>
  );

  if (loading) {
    return <div>Loading...</div>;
  }

  if (!!user && router.asPath === "/") {
    return baseNav;
  } else if (!!user) return wrapperContent;

  return baseNav;
};


实用文件SimpleCTA.tsx

import { Box, Button, Flex, Heading, Link, Text } from "@chakra-ui/react";
import NextLink from "next/link";
import * as React from "react";
import { Image } from "@chakra-ui/react";
import logo from "../../../public/favicon/main_logo.svg";

export const SimpleCTA: React.FC = () => (
  <Box as="section">
    <Box
      maxW="2xl"
      mx="auto"
      px={{ base: "6", lg: "8" }}
      py={{ base: "16", sm: "20" }}
      textAlign="center"
    >
      <Heading as="h2" size="3xl" fontWeight="extrabold" letterSpacing="tight">
        <Flex flexFlow="row nowrap" alignItems="center" justifyContent="center">
          <Heading
            as="h1"
            maxWidth="55%"
            flexShrink={3}
            fontSize="calc(25% + 4.5vw - 40%)"
            textAlign="center"
          >
            something
          </Heading>
          <Image
            width="calc(16% + 8vw - 20%)"
            flexShrink={1}
            src={logo}
            ml="3"
            alt="sometTextForImageMaybe"
          />
        </Flex>
      </Heading>
      <Text font="bold" fontSize="calc(10% + 2.5vw - 5%)">
        Coming soon.
      </Text>
      <NextLink href="/register">
        <Button
          color="tints.800"
          bg="tints.400"
          p="3"
          py="2"
          mt="4"
          size="lg"
          font="bold"
          variant="link"
          _hover={{ color: "tints.600" }}
        >
          <Link style={{ textDecoration: "none" }}>register</Link>
        </Button>
      </NextLink>
    </Box>
  </Box>
);


【问题讨论】:

    标签: jestjs next.js apollo-client chakra-ui


    【解决方案1】:

    如果您有错误"Nothing return from render",则表示代码初始化时没有“返回” = 错误。

    您有 Layout.tsxif 条件。您的错误表明代码逻辑从您的 if 条件中退出。检查你的if statements

    提示:想象你有变量的下一个值:

    console.log(user) // imaging it returns true
    console.log(router.asPath) // imaging it returns "blabla
    

    使用上述值,您将出现“无返回”错误

    【讨论】:

    • 我认为这可能与 HOC 放置有关,返回的所有内容都是 JSX 元素。即使使用典型的 JSX 内在元素删除条件逻辑也会产生相同的错误。
    猜你喜欢
    • 2018-04-05
    • 2021-01-01
    • 2019-04-14
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 2018-07-09
    • 2020-06-25
    • 1970-01-01
    相关资源
    最近更新 更多