Next.js 14页面路由应用Jest测试:getStaticProps环境变量不生效问题
问题
我有一个基于Next 14 page router的简单应用,想通过直接给页面传props的方式用Jest做UI测试,同时不想触发getStaticProps函数。我尝试在测试环境里用process.env.NODE_ENV让getStaticProps直接返回,但执行npm test时发现,getStaticProps里的process.env.NODE_ENV始终不是test,导致数据库相关的代码报错;但只要注释掉getStaticProps里的所有代码,测试就能正常通过。
首页代码(index.tsx):
const Home = (props: dataType) => { const data = props.posts; if(data.length === 0) return <p style={{textAlign:"center"}}> Loading ...</p> return ( <div className={classes.home}> <h1 className={classes["home--header"]}>Blog Post App</h1> <h3 className={classes["home--header"]}>showing blog posts</h3> <div className={classes['home--main']}> {data.map(post=>{ return <BlogCard key={post["_id"].toString()} id={post["_id"].toString()} title={post.title} text={post.text} /> })} </div> </div> ); }; export async function getStaticProps(){ console.log(process.env.NODE_ENV); if(process.env.NODE_ENV=== "test") return; const client = await clientPromise; const db = client.db("blogpost"); const postCollection = db.collection("posts"); const allPosts = await postCollection.find({}).toArray(); return { props:{posts:JSON.parse(JSON.stringify(allPosts))}, revalidate:60*5 }; }
测试代码(home.test.tsx):
import { render, screen } from "@testing-library/react"; import '@testing-library/jest-dom' import Home from "@/pages/index"; describe("Home",(()=>{ test("testing page uses correct Env",()=>{ const test_env = process.env.NODE_ENV; expect(test_env).toBe("test"); // 这个测试能通过 }); test("home page has correct heading", () => { render( <Home posts={[ { _id: "1", title: "test post", text: "this is a test for Home page" }, ]} /> ); const heading = screen.getByRole("heading",{name:/blog post app/i}); expect(heading).toBeInTheDocument(); const postTitle = screen.getByTestId("postTitle"); expect(postTitle).toBeInTheDocument(); }); }));
解决方案
1. 显式设置测试环境变量
Jest默认会把NODE_ENV设为test,但Next.js处理页面组件时可能存在环境变量隔离。可以在Jest配置文件中显式注入:
- 在
jest.config.js中确保测试环境为jsdom:
module.exports = { testEnvironment: 'jsdom', setupFiles: ['./jest.setup.js'], // 其他配置项 };
- 在
jest.setup.js中强制设置环境变量:
process.env.NODE_ENV = 'test';
2. Mock getStaticProps函数
测试时直接Mock掉getStaticProps,不让它执行数据库逻辑:
import { render, screen } from "@testing-library/react"; import '@testing-library/jest-dom'; import Home from "@/pages/index"; // Mock getStaticProps,阻止其执行原逻辑 jest.mock('@/pages/index', () => { const original = jest.requireActual('@/pages/index'); return { ...original, getStaticProps: jest.fn().mockResolvedValue({ props: { posts: [] } }), }; }); describe("Home", () => { test("testing page uses correct Env", () => { expect(process.env.NODE_ENV).toBe("test"); }); test("home page has correct heading", () => { render( <Home posts={[ { _id: "1", title: "test post", text: "this is a test for Home page" }, ]} /> ); const heading = screen.getByRole("heading", { name: /blog post app/i }); expect(heading).toBeInTheDocument(); const postTitle = screen.getByTestId("postTitle"); expect(postTitle).toBeInTheDocument(); }); });
3. 分离UI组件与数据逻辑
把页面的UI部分抽成独立组件,彻底和getStaticProps解耦,测试时直接针对UI组件:
- 新建
components/HomeUI.tsx:
const HomeUI = (props: dataType) => { const data = props.posts; if(data.length === 0) return <p style={{textAlign:"center"}}> Loading ...</p> return ( <div className={classes.home}> <h1 className={classes["home--header"]}>Blog Post App</h1> <h3 className={classes["home--header"]}>showing blog posts</h3> <div className={classes['home--main']}> {data.map(post=>{ return <BlogCard key={post["_id"].toString()} id={post["_id"].toString()} title={post.title} text={post.text} /> })} </div> </div> ); }; export default HomeUI;
- 修改
pages/index.tsx:
import HomeUI from '@/components/HomeUI'; export default function Home(props: dataType) { return <HomeUI {...props} />; } export async function getStaticProps(){ console.log(process.env.NODE_ENV); if(process.env.NODE_ENV=== "test") return; const client = await clientPromise; const db = client.db("blogpost"); const postCollection = db.collection("posts"); const allPosts = await postCollection.find({}).toArray(); return { props:{posts:JSON.parse(JSON.stringify(allPosts))}, revalidate:60*5 }; }
- 测试文件修改为测试
HomeUI:
import { render, screen } from "@testing-library/react"; import '@testing-library/jest-dom'; import HomeUI from "@/components/HomeUI"; describe("HomeUI", () => { test("home page has correct heading", () => { render( <HomeUI posts={[ { _id: "1", title: "test post", text: "this is a test for Home page" }, ]} /> ); const heading = screen.getByRole("heading", { name: /blog post app/i }); expect(heading).toBeInTheDocument(); const postTitle = screen.getByTestId("postTitle"); expect(postTitle).toBeInTheDocument(); }); });
4. 检查Next.js测试配置
确保项目使用@testing-library/jest-dom和jsdom测试环境,避免服务器端环境变量干扰,同时确保next/jest配置正确(如果使用官方测试工具链)。
内容的提问来源于stack exchange,提问作者AmirHossein_Khakshouri
相关产品推荐
相关产品推荐

