我正在撰寫 Jest/測驗庫測驗。
假設我們有一個名為BenchmarksPage.
請看它回傳陳述句的第一行。
import {
Box,
capitalize,
Container,
FormControl,
InputLabel,
MenuItem,
Select,
} from '@material-ui/core';
import { NextPage } from 'next';
import React, { useCallback, useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import RequireScope from 'src/components/authentication/RequireScope';
import BenchmarkTable from 'src/components/benchmark/BenchmarkTable';
import DashboardLayout from 'src/components/dashboard/DashboardLayout';
import Heading from 'src/components/Heading';
import useSettings from 'src/hooks/useSettings';
import gtm from 'src/lib/gtm';
import { useDispatch, useSelector } from 'src/store';
import { getAllRollingTwelveCalcs } from 'src/store/rolling-twelve/rolling-twelve.thunk';
import { Timeframe, timeframeMap } from 'src/types/benchmark';
const BenchmarksPage: NextPage = () => {
const { settings } = useSettings();
const dispatch = useDispatch();
const [selectedTimeframe, setSelectedTimeframe] = useState<Timeframe>(
Timeframe.Monthly,
);
const company = useSelector((state) => state.company.current);
useEffect(() => {
gtm.push({ event: 'page_view' });
}, []);
useEffect(() => {
dispatch(getAllRollingTwelveCalcs());
}, [company]);
const handleTimeframeChange = useCallback(
(
event: React.ChangeEvent<{
name?: string;
value: Timeframe;
event: Event | React.SyntheticEvent<Element, Event>;
}>,
) => {
setSelectedTimeframe(event.target.value);
},
[],
);
return (
<RequireScope scopes={['query:benchmark-calcs']}>
<DashboardLayout>
<Helmet>
<title>Benchmarks</title>
</Helmet>
<Container maxWidth={settings.compact ? 'xl' : false}>
<Box
sx={{
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'space-between',
mb: 4,
}}
>
<Heading>Benchmarks</Heading>
<FormControl sx={{ width: 300 }}>
<InputLabel>Timeframe</InputLabel>
<Select
sx={{ background: '#ffffff', maxWidth: 400 }}
value={selectedTimeframe}
label="Timeframe"
onChange={handleTimeframeChange}
>
{[...timeframeMap.keys()].map((timeframe) => (
<MenuItem key={timeframe} value={timeframe}>
{capitalize(timeframe)}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
<BenchmarkTable timeframe={selectedTimeframe} />
</Container>
</DashboardLayout>
</RequireScope>
);
};
export default BenchmarksPage;
Note that its return value is wrapped with RequireScope
RequireScope will only render its children when user is authenticated
RequireScope:
import React, { useEffect, useState } from 'react';
import useAuth from 'src/hooks/useAuth';
export interface RequireScopeProps {
scopes: string[];
}
const RequireScope: React.FC<RequireScopeProps> = React.memo((props) => {
const { children, scopes } = props;
const { isInitialized, isAuthenticated, permissions } = useAuth();
const [isPermitted, setIsPermitted] = useState(false);
useEffect(() => {
if (process.env.NEXT_PUBLIC_IS_LOCAL) {
setIsPermitted(true);
}
}, []);
useEffect(() => {
if (isAuthenticated && isInitialized) {
(async () => {
const hasPermissions = scopes
.map((s) => {
return permissions.includes(s);
})
.filter(Boolean);
if (hasPermissions.length === scopes.length) {
setIsPermitted(true);
}
})();
}
}, [isAuthenticated, isInitialized, scopes, permissions]);
if (isPermitted) {
return <>{children}</>;
}
return null;
});
export default RequireScope;
We just need isPermitted to be set to true
(useAuth uses JWT to sign in a user btw)
Now when I render the BenchmarksPage using Testing Library's render method,
it does not get rendered on the jsdom because the
'isPermitted' is still false in RequireScope.
So, in order to make isPermitted = true
I have set
NEXT_PUBLIC_IS_LOCAL=true
in .env.development
According to the first useEffect in RequireScope, isPermitted should be true now.
Yet, the component is still not rendered, returning
<body></div></body>
This still means isPermitted is false.
What have I tried:
I have also tried using .env.local
I can ensure you that my setUps are all correct (jest.config, using MockProvider to wrap BenchmarksPage etc.)
Why isn't .env.development working, and making isPermitted = true ?
在我的理解中,一切在邏輯上都是正確的。
編輯:我試過寫作
NEXT_PUBLIC_IS_LOCAL=真
在 .env.test 檔案中
編輯 - 答案:
必須設定
import { loadEnvConfig } from '@next/env';
export default async (): Promise<void> => {
loadEnvConfig(process.env.PWD);
};
在 setupEnv.ts 檔案中。
然后在 package.json 中,添加 globalSetup (因為我不使用 jest.config.js -> eslint 與 tsconfig 一起搞砸了)
"jest": {
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/src/$1"
},
"testEnvironment": "jsdom",
"globalSetup": "<rootDir>/test/setupEnv.ts"
},
uj5u.com熱心網友回復:
如果您的環境變數在運行開發服務器時作業,但在測驗時不起作用,這是因為 Next 在單元測驗時沒有為 Jest 設定變數。
首先,創建一個.env.test,設定僅用于測驗的環境變數。
然后,為了在測驗環境中設定環境,您必須將其添加到您的測驗入口點:
// jest.config.js
module.exports = {
globalSetup: '<rootDir>/__test__/setupEnv.js'
}
// __test__/setupEnv.js
import { loadEnvConfig } from '@next/env'
export default async () => {
const projectDir = process.cwd()
loadEnvConfig(projectDir)
}
請注意,.env.local在測驗期間未加載
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/457644.html
