chore: run tests and storybook in StrictMode (#3352)

Co-authored-by: WK Wong <wingkwong.code@gmail.com>
This commit is contained in:
chirokas 2024-09-08 15:35:29 +08:00 committed by GitHub
parent d621b2923e
commit 659cdcf02d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 140 additions and 14 deletions

View File

@ -25,6 +25,7 @@
"build:sb": "pnpm --filter @nextui-org/storybook build",
"start:sb": "pnpm --filter @nextui-org/storybook start",
"test": "jest --verbose --config ./jest.config.js",
"test:strict": "cross-env STRICT_MODE=true pnpm test",
"typecheck": "turbo typecheck",
"lint": "pnpm lint:pkg && pnpm lint:docs",
"lint:pkg": "eslint -c .eslintrc.json ./packages/**/*.{ts,tsx}",
@ -54,7 +55,6 @@
"devDependencies": {
"@babel/cli": "^7.14.5",
"@babel/core": "^7.16.7",
"tsx": "^3.8.2",
"@babel/plugin-proposal-object-rest-spread": "^7.15.6",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/preset-env": "^7.14.5",
@ -69,6 +69,7 @@
"@react-bootstrap/babel-preset": "^2.1.0",
"@react-types/link": "^3.4.4",
"@react-types/shared": "3.23.1",
"@storybook/react": "^7.4.6",
"@swc-node/jest": "^1.5.2",
"@swc/core": "^1.3.35",
"@swc/jest": "^0.2.24",
@ -85,10 +86,10 @@
"@types/testing-library__jest-dom": "5.14.5",
"@typescript-eslint/eslint-plugin": "^5.42.0",
"@typescript-eslint/parser": "^5.42.0",
"@storybook/react": "^7.4.6",
"chalk": "^4.1.2",
"concurrently": "^7.6.0",
"commitlint-plugin-function-rules": "^1.7.1",
"concurrently": "^7.6.0",
"cross-env": "^7.0.3",
"eslint": "^7.29.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-config-airbnb-typescript": "^12.3.1",
@ -106,8 +107,6 @@
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-unused-imports": "^2.0.0",
"npm-check-updates": "^16.10.18",
"intl-messageformat": "^10.1.0",
"execa": "^5.1.1",
"find-up": "^6.3.0",
"fs-extra": "^10.0.0",
@ -115,10 +114,12 @@
"graceful-fs": "^4.2.6",
"gray-matter": "^4.0.3",
"husky": "^8.0.1",
"intl-messageformat": "^10.1.0",
"jest": "^28.1.1",
"jest-environment-jsdom": "^28.1.1",
"jest-watch-typeahead": "1.1.0",
"lint-staged": "^13.0.3",
"npm-check-updates": "^16.10.18",
"npm-run-all": "^4.1.5",
"p-iteration": "^1.1.8",
"parcel": "^2.3.1",
@ -131,6 +132,7 @@
"rimraf": "^3.0.2",
"shelljs": "^0.8.4",
"tsup": "6.4.0",
"tsx": "^3.8.2",
"turbo": "1.6.3",
"typescript": "^4.9.5",
"webpack": "^5.53.0",

View File

@ -0,0 +1,29 @@
import type { PropsWithChildren } from "react"
import { addons, makeDecorator } from "@storybook/preview-api"
import { getQueryParams } from "@storybook/preview-api"
import React, { StrictMode, useEffect, useState } from "react"
function StrictModeDecorator({ children }: PropsWithChildren<any>) {
const [isStrict, setStrict] = useState(() => getQueryParams()?.strict === "true")
useEffect(() => {
const channel = addons.getChannel()
channel.on("strict/updated", setStrict)
return () => {
channel.removeListener("strict/updated", setStrict)
}
}, [])
return isStrict ? <StrictMode>{children}</StrictMode> : children
}
export const withStrictModeSwitcher = makeDecorator({
name: "withStrictModeSwitcher",
parameterName: "strictModeSwitcher",
wrapper: (getStory, context) => {
return <StrictModeDecorator>{getStory(context)}</StrictModeDecorator>
},
})

View File

@ -0,0 +1,55 @@
import type { API } from "@storybook/manager-api";
import { addons, types } from "@storybook/manager-api";
import React, { useEffect, useState } from "react";
const ADDON_ID = "StrictModeSwitcher";
function StrictModeSwitcher({ api }: { api: API }) {
const [isStrict, setStrict] = useState(() => api.getQueryParam("strict") === "true");
const onChange = () => setStrict((val) => !val);
useEffect(() => {
const channel = api.getChannel();
channel?.emit("strict/updated", isStrict);
api.setQueryParams({
strict: String(isStrict),
});
}, [isStrict]);
return (
<div
style={{
alignItems: "center",
display: "flex",
fontSize: "0.75rem",
fontWeight: 600,
lineHeight: "1rem",
}}
title="Enable Strict Mode"
>
<label htmlFor="strictmode">StrictMode:</label>
<input
checked={isStrict}
id="strictmode"
name="strictmode"
onChange={onChange}
type="checkbox"
/>
</div>
);
}
if (process.env.NODE_ENV !== "production") {
addons.register(ADDON_ID, (api) => {
addons.add(ADDON_ID, {
match: ({ viewMode }) => !!viewMode?.match(/^(story|docs)$/),
render: () => <StrictModeSwitcher api={api} />,
title: "Strict Mode Switcher",
type: types.TOOL,
});
});
}

View File

@ -11,14 +11,14 @@ module.exports = {
getAbsolutePath("@storybook/addon-essentials"),
getAbsolutePath("@storybook/addon-links"),
getAbsolutePath("storybook-dark-mode"),
getAbsolutePath("@storybook/addon-mdx-gfm")
getAbsolutePath("@storybook/addon-mdx-gfm"),
"./addons/react-strict-mode/register",
],
framework: {
name: getAbsolutePath("@storybook/react-vite"),
options: {}
},
core: {
disableTelemetry: true
disableTelemetry: true,
},
typescript: {
reactDocgen: false,

View File

@ -4,6 +4,7 @@ import {NextUIProvider} from "@nextui-org/system/src/provider";
import type {Preview} from "@storybook/react";
import "./style.css";
import { withStrictModeSwitcher } from "./addons/react-strict-mode";
const decorators: Preview["decorators"] = [
(Story, {globals: {locale, disableAnimation}}) => {
@ -19,6 +20,7 @@ const decorators: Preview["decorators"] = [
</NextUIProvider>
);
},
...(process.env.NODE_ENV !== "production" ? [withStrictModeSwitcher] : []),
];
const commonTheme = {

View File

@ -44,6 +44,8 @@
"@storybook/addon-links": "^7.4.6",
"@storybook/addon-mdx-gfm": "^7.4.6",
"@storybook/cli": "^7.4.6",
"@storybook/manager-api": "^7.6.17",
"@storybook/preview-api": "^7.6.17",
"@storybook/react": "^7.4.6",
"@storybook/react-vite": "^7.4.6",
"@storybook/theming": "^7.4.6",

43
pnpm-lock.yaml generated
View File

@ -120,6 +120,9 @@ importers:
concurrently:
specifier: ^7.6.0
version: 7.6.0
cross-env:
specifier: ^7.0.3
version: 7.0.3
eslint:
specifier: ^7.29.0
version: 7.32.0
@ -3634,6 +3637,12 @@ importers:
'@storybook/cli':
specifier: ^7.4.6
version: 7.6.17(encoding@0.1.13)
'@storybook/manager-api':
specifier: ^7.6.17
version: 7.6.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@storybook/preview-api':
specifier: ^7.6.17
version: 7.6.17
'@storybook/react':
specifier: ^7.4.6
version: 7.6.17(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@4.9.5)
@ -5201,9 +5210,11 @@ packages:
'@humanwhocodes/config-array@0.5.0':
resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==}
engines: {node: '>=10.10.0'}
deprecated: Use @eslint/config-array instead
'@humanwhocodes/object-schema@1.2.1':
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
deprecated: Use @eslint/object-schema instead
'@iconify/icons-solar@1.2.3':
resolution: {integrity: sha512-dots93IzoaOrJ8aUD2YGZ4+Jy+yf5D87CmzSeBkEi/m+WX1klvHqWuw5kyZvVroLOlaIaJXb5nZVaDnhc8XJyQ==}
@ -8146,6 +8157,7 @@ packages:
are-we-there-yet@3.0.1:
resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
@ -9026,6 +9038,11 @@ packages:
crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
cross-env@7.0.3:
resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
hasBin: true
cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
@ -10385,6 +10402,7 @@ packages:
gauge@4.0.4:
resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
@ -10487,13 +10505,16 @@ packages:
glob@7.1.7:
resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
deprecated: Glob versions prior to v9 are no longer supported
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
deprecated: Glob versions prior to v9 are no longer supported
global-dirs@0.1.1:
resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==}
@ -10891,6 +10912,7 @@ packages:
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@ -12646,6 +12668,7 @@ packages:
npmlog@6.0.2:
resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
deprecated: This package is no longer supported.
nprogress@0.2.0:
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
@ -13516,6 +13539,7 @@ packages:
read-package-json@6.0.4:
resolution: {integrity: sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
deprecated: This package is no longer supported. Please use @npmcli/package-json instead.
read-pkg-up@7.0.1:
resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
@ -13811,14 +13835,17 @@ packages:
rimraf@2.6.3:
resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@5.0.5:
@ -20769,7 +20796,7 @@ snapshots:
'@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.2.5
'@types/node': 15.14.9
'@types/buble@0.20.5':
dependencies:
@ -20789,7 +20816,7 @@ snapshots:
'@types/connect@3.4.38':
dependencies:
'@types/node': 20.2.5
'@types/node': 15.14.9
'@types/cross-spawn@6.0.6':
dependencies:
@ -20833,7 +20860,7 @@ snapshots:
'@types/express-serve-static-core@4.19.0':
dependencies:
'@types/node': 20.2.5
'@types/node': 15.14.9
'@types/qs': 6.9.14
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
@ -21021,12 +21048,12 @@ snapshots:
'@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.2.5
'@types/node': 15.14.9
'@types/serve-static@1.15.7':
dependencies:
'@types/http-errors': 2.0.4
'@types/node': 20.2.5
'@types/node': 15.14.9
'@types/send': 0.17.4
'@types/shelljs@0.8.15':
@ -22568,6 +22595,10 @@ snapshots:
crelt@1.0.6: {}
cross-env@7.0.3:
dependencies:
cross-spawn: 7.0.3
cross-spawn@5.1.0:
dependencies:
lru-cache: 4.1.5
@ -27902,7 +27933,7 @@ snapshots:
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 20.2.5
'@types/node': 15.14.9
long: 5.2.3
proxy-addr@2.0.7:

View File

@ -1,4 +1,5 @@
import "@testing-library/jest-dom/extend-expect";
import { configure } from "@testing-library/react";
const {getComputedStyle} = window;
window.getComputedStyle = (elt) => getComputedStyle(elt);
@ -29,3 +30,7 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
configure({
reactStrictMode: process.env.STRICT_MODE === "true",
});