@modern-js/main-doc 0.0.0-nightly-20240902170725 → 0.0.0-nightly-20240904170727
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/en/components/init-app.mdx +0 -1
- package/docs/en/components/init-rspack-app.mdx +0 -1
- package/docs/en/configure/app/tools/tailwindcss.mdx +1 -1
- package/docs/en/guides/advanced-features/_meta.json +0 -1
- package/docs/en/guides/advanced-features/rsbuild-plugin.mdx +2 -2
- package/docs/en/guides/advanced-features/rspack-start.mdx +6 -14
- package/docs/en/guides/basic-features/_meta.json +25 -9
- package/docs/en/guides/basic-features/css/_meta.json +1 -0
- package/docs/en/guides/basic-features/css/css-in-js.mdx +34 -0
- package/docs/en/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -4
- package/docs/en/guides/basic-features/css/css.mdx +25 -0
- package/docs/en/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +5 -66
- package/docs/en/guides/basic-features/data/data-fetch.mdx +1 -1
- package/docs/en/guides/basic-features/data/data-write.mdx +1 -1
- package/docs/en/guides/basic-features/debug/_meta.json +1 -0
- package/docs/en/guides/basic-features/debug/rsdoctor.mdx +57 -0
- package/docs/en/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +2 -0
- package/docs/en/guides/basic-features/static-assets/_meta.json +1 -0
- package/docs/en/guides/basic-features/static-assets.mdx +1 -1
- package/docs/en/guides/basic-features/testing/_meta.json +1 -0
- package/docs/en/guides/basic-features/testing/cypress.mdx +95 -0
- package/docs/en/guides/basic-features/testing/jest.mdx +148 -0
- package/docs/en/guides/basic-features/testing/playwright.mdx +111 -0
- package/docs/en/guides/basic-features/testing/vitest.mdx +100 -0
- package/docs/en/guides/get-started/quick-start.mdx +1 -1
- package/docs/en/guides/get-started/tech-stack.mdx +4 -4
- package/docs/en/guides/topic-detail/generator/create/config.mdx +0 -10
- package/docs/en/guides/topic-detail/generator/create/use.mdx +0 -1
- package/docs/en/tutorials/first-app/c03-css.mdx +1 -1
- package/docs/zh/components/init-app.mdx +0 -1
- package/docs/zh/components/init-rspack-app.mdx +0 -1
- package/docs/zh/configure/app/tools/tailwindcss.mdx +1 -1
- package/docs/zh/guides/advanced-features/_meta.json +0 -1
- package/docs/zh/guides/advanced-features/rsbuild-plugin.mdx +2 -2
- package/docs/zh/guides/advanced-features/rspack-start.mdx +7 -16
- package/docs/zh/guides/basic-features/_meta.json +25 -9
- package/docs/zh/guides/basic-features/css/_meta.json +1 -0
- package/docs/zh/guides/basic-features/css/css-in-js.mdx +34 -0
- package/docs/zh/guides/basic-features/css/css.mdx +25 -0
- package/docs/zh/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +3 -64
- package/docs/zh/guides/basic-features/debug/_meta.json +1 -0
- package/docs/zh/guides/basic-features/debug/rsdoctor.mdx +57 -0
- package/docs/zh/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +1 -1
- package/docs/zh/guides/basic-features/routes.mdx +1 -1
- package/docs/zh/guides/basic-features/static-assets/_meta.json +1 -0
- package/docs/zh/guides/basic-features/static-assets.mdx +2 -6
- package/docs/zh/guides/basic-features/testing/_meta.json +1 -0
- package/docs/zh/guides/basic-features/testing/cypress.mdx +95 -0
- package/docs/zh/guides/basic-features/testing/jest.mdx +148 -0
- package/docs/zh/guides/basic-features/testing/playwright.mdx +112 -0
- package/docs/zh/guides/basic-features/testing/vitest.mdx +100 -0
- package/docs/zh/guides/get-started/quick-start.mdx +1 -1
- package/docs/zh/guides/get-started/tech-stack.mdx +8 -8
- package/docs/zh/guides/topic-detail/generator/create/config.mdx +0 -10
- package/docs/zh/guides/topic-detail/generator/create/use.mdx +0 -1
- package/docs/zh/tutorials/first-app/c03-css.mdx +1 -1
- package/i18n.json +16 -4
- package/package.json +4 -4
- /package/docs/en/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
- /package/docs/en/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
- /package/docs/en/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
- /package/docs/en/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
- /package/docs/en/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
|
@@ -1,65 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
sidebar_position: 1
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# 样式开发
|
|
6
|
-
|
|
7
|
-
Modern.js 内置多种常用的 CSS 开发方案,包括 Less / Sass / Stylus 预处理器、PostCSS、CSS Modules、CSS-in-JS 和 Tailwind CSS。
|
|
8
|
-
|
|
9
|
-
## 使用 Less、Sass 和 Stylus
|
|
10
|
-
|
|
11
|
-
Modern.js 内置了社区流行的 CSS 预处理器,包括 Less 和 Sass。
|
|
12
|
-
|
|
13
|
-
默认情况下,你不需要对 Less 和 Sass 进行任何配置。如果你有自定义 loader 配置的需求,可以通过配置 [tools.less](/configure/app/tools/less)、[tools.sass](/configure/app/tools/sass) 来进行设置。
|
|
14
|
-
|
|
15
|
-
你也可以在 Modern.js 中使用 Stylus,只需要安装 Rsbuild 提供的 Stylus 插件即可,使用方式请参考 [Stylus 插件](https://rsbuild.dev/zh/plugins/list/plugin-stylus)。
|
|
16
|
-
|
|
17
|
-
## 使用 PostCSS
|
|
18
|
-
|
|
19
|
-
Modern.js 内置了 [PostCSS](https://postcss.org/) 来转换 CSS 代码。
|
|
20
|
-
|
|
21
|
-
请阅读 [Rsbuild - 使用 PostCSS](https://rsbuild.dev/zh/guide/basic/css-usage#%E4%BD%BF%E7%94%A8-postcss) 了解更多用法。
|
|
22
|
-
|
|
23
|
-
## 使用 CSS Modules
|
|
24
|
-
|
|
25
|
-
请阅读 [使用 CSS Modules](/guides/basic-features/css-modules) 章节来了解 CSS Modules 的完整用法。
|
|
26
|
-
|
|
27
|
-
## 使用 CSS-in-JS
|
|
28
|
-
|
|
29
|
-
CSS-in-JS 是一种可以将 CSS 样式写在 JS 文件里的技术。
|
|
30
|
-
|
|
31
|
-
Modern.js 集成了社区常用的 CSS-in-JS 实现库 [styled-components](https://styled-components.com/),它使用 JavaScript 的新特性 [Tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates) 编写组件的 CSS 样式。可以直接从 `@modern-js/runtime/styled` 引入 [styled-components](https://styled-components.com/) 的 API 进行使用。
|
|
32
|
-
|
|
33
|
-
当需要编写一个内部字体为红色的 `div` 组件时,可以如下实现:
|
|
34
|
-
|
|
35
|
-
```js
|
|
36
|
-
import styled from '@modern-js/runtime/styled';
|
|
37
|
-
|
|
38
|
-
const RedDiv = styled.div`
|
|
39
|
-
color: red;
|
|
40
|
-
`;
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
当需要根据组件的 `props` 动态设置组件样式时,例如 `props` 的属性 `primary` 为 `true` 时,按钮的颜色为白色,其他情况为红色,实现代码如下:
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
import styled from '@modern-js/runtime/styled';
|
|
47
|
-
|
|
48
|
-
const Button = styled.button`
|
|
49
|
-
color: ${props => (props.primary ? 'white' : 'red')};
|
|
50
|
-
font-size: 1em;
|
|
51
|
-
`;
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
关于 styled-components 的更多用法,请参考 [styled-components 官网](https://styled-components.com/)。
|
|
55
|
-
|
|
56
|
-
Modern.js 内部集成了 Babel 的 [babel-plugin-styled-components](https://github.com/styled-components/babel-plugin-styled-components) 插件,你可以通过 [tools.styledComponents](/configure/app/tools/styled-components) 对插件进行配置。
|
|
57
|
-
|
|
58
|
-
:::tip 提示
|
|
59
|
-
如果需要使用 [styled-jsx](https://www.npmjs.com/package/styled-jsx)、[Emotion](https://emotion.sh/) 等其他 CSS-in-JS 库,需要先安装对应库的依赖。具体使用方式请参考对应库的官网。
|
|
60
|
-
:::
|
|
61
|
-
|
|
62
|
-
## 使用 Tailwind CSS
|
|
1
|
+
# 使用 Tailwind CSS
|
|
63
2
|
|
|
64
3
|
[Tailwind CSS](https://tailwindcss.com/) 是一个以 Utility Class 为基础的 CSS 框架和设计系统,可以快速地为组件添加常用样式,同时支持主题样式的灵活扩展。
|
|
65
4
|
|
|
@@ -153,7 +92,7 @@ Tailwind CSS 官方提供了 [Tailwind CSS IntelliSense](https://github.com/tail
|
|
|
153
92
|
1. 在 VS Code 中安装 [Tailwind CSS IntelliSense](https://github.com/tailwindlabs/tailwindcss-intellisense) 插件。
|
|
154
93
|
2. 如果项目的根目录没有 `tailwind.config.{ts,js}` 文件,那么你需要创建该文件,并写入当前项目的 Tailwind CSS 配置,否则 IDE 插件将无法正确生效。
|
|
155
94
|
|
|
156
|
-
|
|
95
|
+
## Tailwind CSS 版本
|
|
157
96
|
|
|
158
97
|
Modern.js 同时支持 Tailwind CSS v2 和 v3 版本,框架会识别项目 `package.json` 中的 `tailwindcss` 依赖版本,并启用相应的配置。默认情况下,我们会为你安装 Tailwind CSS v3 版本。
|
|
159
98
|
|
|
@@ -162,7 +101,7 @@ Modern.js 同时支持 Tailwind CSS v2 和 v3 版本,框架会识别项目 `pa
|
|
|
162
101
|
- [Tailwind CSS v3.0](https://tailwindcss.com/blog/tailwindcss-v3)
|
|
163
102
|
- [Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide)
|
|
164
103
|
|
|
165
|
-
|
|
104
|
+
## 浏览器兼容性
|
|
166
105
|
|
|
167
106
|
Tailwind CSS v2 和 v3 均不支持 IE 11 浏览器,相关背景请参考:
|
|
168
107
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["mock", "proxy", "rsdoctor", "using-storybook"]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PackageManagerTabs } from '@theme';
|
|
2
|
+
|
|
3
|
+
# 使用 Rsdoctor
|
|
4
|
+
|
|
5
|
+
Rsdoctor 是一个支持 Webpack 及 Rspack 构建分析工具。在 Modern.js 中,我们推荐使用 Rsdoctor 来对构建过程与构建产物进行诊断和分析。
|
|
6
|
+
|
|
7
|
+
## 安装依赖
|
|
8
|
+
|
|
9
|
+
根据项目是 Rspack 或 Webpack 构建,选择对应的插件安装。
|
|
10
|
+
|
|
11
|
+
### Rspack 插件
|
|
12
|
+
|
|
13
|
+
<PackageManagerTabs command="add @rsdoctor/rspack-plugin -D" />
|
|
14
|
+
|
|
15
|
+
### Webpack 插件
|
|
16
|
+
|
|
17
|
+
<PackageManagerTabs command="add @rsdoctor/webpack-plugin -D" />
|
|
18
|
+
|
|
19
|
+
## 注册插件
|
|
20
|
+
|
|
21
|
+
在 `modern.config.ts` 中,你可以通过 `tools.bundlerChain` 来注册 Rspack 或 Webpack 插件,参考:
|
|
22
|
+
|
|
23
|
+
```ts title="modern.config.ts"
|
|
24
|
+
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
// ...
|
|
28
|
+
tools: {
|
|
29
|
+
rspack(config, { appendPlugins }) {
|
|
30
|
+
// 仅在 RSDOCTOR 为 true 时注册插件,因为插件会增加构建耗时
|
|
31
|
+
if (process.env.RSDOCTOR) {
|
|
32
|
+
appendPlugins(
|
|
33
|
+
new RsdoctorRspackPlugin({
|
|
34
|
+
// 插件选项
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
:::note
|
|
44
|
+
上述代码是使用 Rspack 时的示例,如果使用 Webpack 请自行切换插件。
|
|
45
|
+
:::
|
|
46
|
+
|
|
47
|
+
## 执行构建
|
|
48
|
+
|
|
49
|
+
在你可以在项目内执行 build 命令,在完成构建后,Rsdoctor 会自动打开本次构建的分析页面。
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
RSDOCTOR=true npm run build
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 相关文档
|
|
56
|
+
|
|
57
|
+
更多内容请查阅 [Rsdoctor 官网文档](https://rsdoctor.dev/)。
|
|
@@ -229,4 +229,4 @@ Modern.js 的配置文件默认为 `modern.config.(j|t)s`,配置请查看 [mod
|
|
|
229
229
|
|
|
230
230
|
若原来项目中包含了 Babel 等配置,需要对应的写在 modern 配置中,大部分 Babel 配置已经包含进了 Modern.js。
|
|
231
231
|
|
|
232
|
-
安装完成后进行相应的[配置](/guides/
|
|
232
|
+
安装完成后进行相应的[配置](/guides/basic-features/debug/using-storybook#配置)。
|
|
@@ -265,7 +265,7 @@ export default Page404;
|
|
|
265
265
|
|
|
266
266
|
## 路由句柄配置
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
某些场景下,每个路由会拥有属于自己的数据,应用需要在其他组件中获取匹配到的路由的这些数据。一个常见的例子是在布局中获取到匹配路由的面包屑信息。
|
|
269
269
|
|
|
270
270
|
Modern.js 提供了独立的约定,每个 `Layout`, `$` 或 `Page` 文件都可以定义一个自己的 `config` 文件,如 `page.config.ts`,该文件中我们约定了一个具名导出 `handle`,这个字段中你可以定义任意属性:
|
|
271
271
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["json-files", "svg-assets", "wasm-assets"]
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
sidebar_position: 10
|
|
3
|
-
---
|
|
4
|
-
|
|
5
1
|
# 引用静态资源
|
|
6
2
|
|
|
7
3
|
Modern.js 支持在代码中引用图片、字体、媒体类型的静态资源。
|
|
@@ -21,7 +17,7 @@ Modern.js 支持在代码中引用图片、字体、媒体类型的静态资源
|
|
|
21
17
|
如果你需要引用其他格式的静态资源,请参考 [扩展静态资源类型](#扩展静态资源类型)。
|
|
22
18
|
|
|
23
19
|
:::tip SVG 图片
|
|
24
|
-
SVG 图片是一种特殊情况,Modern.js 提供了 SVG 转 React 组件的能力,对 SVG 进行单独处理,详见 [引用 SVG 资源](/guides/basic-features/svg-assets.html)。
|
|
20
|
+
SVG 图片是一种特殊情况,Modern.js 提供了 SVG 转 React 组件的能力,对 SVG 进行单独处理,详见 [引用 SVG 资源](/guides/basic-features/static-assets/svg-assets.html)。
|
|
25
21
|
:::
|
|
26
22
|
|
|
27
23
|
## 在 JS 文件中引用
|
|
@@ -162,4 +158,4 @@ console.log(myFile); // "/static/myFile.6c12aba3.pdf"
|
|
|
162
158
|
| PNG | 无损压缩,不会丢失图片细节,不失真,支持半透明 | 不适合色表复杂的图片 | 适合颜色数量少,边界层次分明的图片,适合用在 logo、icon、透明图等场景 |
|
|
163
159
|
| JPG | 颜色丰富 | 有损压缩,会导致图片失真,不支持透明度 | 适合颜色数量多,颜色带有渐变、过度复杂的图片,适合用在人像照片、风景图等场景 |
|
|
164
160
|
| WebP | 同时支持有损压缩与无损压缩,支持透明度,体积比 PNG 和 JPG 小很多 | iOS 兼容性不好 | 几乎任何场景的像素图片,支持 WebP 的宿主环境,都应该首选 WebP 图片格式 |
|
|
165
|
-
| SVG |
|
|
161
|
+
| SVG | 无损格式,不失真,支持透明度 | 不适合复杂图形 | 适合矢量图,适合用于 icon |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
["playwright", "vitest", "jest", "cypress"]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Cypress
|
|
2
|
+
|
|
3
|
+
Cypress 是一个用于 E2E 测试和组件测试的框架。
|
|
4
|
+
|
|
5
|
+
在 Modern.js 中使用 Cypress 需要先安装依赖,可以执行以下命令:
|
|
6
|
+
|
|
7
|
+
import { PackageManagerTabs } from '@theme';
|
|
8
|
+
|
|
9
|
+
<PackageManagerTabs command={{ npm: "npm install -D cypress", yarn: "yarn add -D cypress", pnpm: "pnpm install -D cypress" }} />
|
|
10
|
+
|
|
11
|
+
接下来,创建 `cypress.config.ts` 文件,并添加以下内容:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { defineConfig } from 'cypress'
|
|
15
|
+
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
e2e: {
|
|
18
|
+
setupNodeEvents(on, config) {},
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 编写测试用例
|
|
24
|
+
|
|
25
|
+
现在,使用 Cypress 来编写一个 E2E 用例,首先创建两张 Modern.js 的页面。
|
|
26
|
+
|
|
27
|
+
```tsx title="routes/page.tsx"
|
|
28
|
+
import { Link } from '@modern-js/runtime/router';
|
|
29
|
+
|
|
30
|
+
const Index = () => (
|
|
31
|
+
<div>
|
|
32
|
+
<h1>Home</h1>
|
|
33
|
+
<Link to="/about">About</Link>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export default Index;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```tsx title="routes/about/page.tsx"
|
|
41
|
+
import { Link } from '@modern-js/runtime/router';
|
|
42
|
+
|
|
43
|
+
const Index = () => (
|
|
44
|
+
<div>
|
|
45
|
+
<h1>About</h1>
|
|
46
|
+
<Link to="/">Home</Link>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export default Index;
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
接下来,创建测试用例文件:
|
|
54
|
+
|
|
55
|
+
```ts title="cypress/e2e/app.cy.ts"
|
|
56
|
+
describe('Navigation', () => {
|
|
57
|
+
it('should navigate to the about page', () => {
|
|
58
|
+
// Start from the index page
|
|
59
|
+
cy.visit('http://localhost:8080/')
|
|
60
|
+
|
|
61
|
+
// Find a link with an href attribute containing "about" and click it
|
|
62
|
+
cy.get('a[href*="about"]').click()
|
|
63
|
+
|
|
64
|
+
// The new url should include "/about"
|
|
65
|
+
cy.url().should('include', '/about')
|
|
66
|
+
|
|
67
|
+
// The new page should contain an h1 with "About"
|
|
68
|
+
cy.get('h1').contains('About')
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
测试文件可能会缺少 API 的类型,你可以参考 [Cypress - Typescript](https://docs.cypress.io/guides/tooling/typescript-support#Configure-tsconfigjson) 文档解决。
|
|
74
|
+
|
|
75
|
+
你可以将命令添加到 `package.json` 中:
|
|
76
|
+
|
|
77
|
+
```json title="package.json"
|
|
78
|
+
{
|
|
79
|
+
"scripts": {
|
|
80
|
+
"test": "cypress open"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 运行测试用例
|
|
86
|
+
|
|
87
|
+
执行上述 `test` 命令,运行测试用例:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
DevTools listening on ws://127.0.0.1:55203/devtools/browser/xxxxx
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Cypress 会打开一个无头浏览器,按照提示你可以找到对应的测试文件,并自动运行 E2E 测试:
|
|
94
|
+
|
|
95
|
+

|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Jest
|
|
2
|
+
|
|
3
|
+
Jest 是一个 JavaScript 测试框架,它主要和 React Testing Library 一起用于单元测试和 Snapshot 测试。
|
|
4
|
+
|
|
5
|
+
在 Modern.js 中使用 Jest 需要先安装依赖,可以执行以下命令:
|
|
6
|
+
|
|
7
|
+
import { PackageManagerTabs } from '@theme';
|
|
8
|
+
|
|
9
|
+
<PackageManagerTabs command={{
|
|
10
|
+
npm: "npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom",
|
|
11
|
+
yarn: "yarn add -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom",
|
|
12
|
+
pnpm: "pnpm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom"
|
|
13
|
+
}} />
|
|
14
|
+
|
|
15
|
+
随后,你可以运行以下命令,这将自动在项目中初始化 Jets,并生成一个基础的 `jest.config.[jt]s` 配置:
|
|
16
|
+
|
|
17
|
+
<PackageManagerTabs command={{
|
|
18
|
+
npm: "npm init jest@latest",
|
|
19
|
+
yarn: "yarn create jest@latest",
|
|
20
|
+
pnpm: "pnpm create jest@latest"
|
|
21
|
+
}} />
|
|
22
|
+
|
|
23
|
+
## 配置文件
|
|
24
|
+
|
|
25
|
+
:::note
|
|
26
|
+
本章节会使用 `.ts` 文件来完成 Jest 测试。
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
相比于其他的测试框架,Jest 在构建层面需要更多的配置,例如处理 JSX 和 ESM 语法,因此首先需要安装一些额外的依赖:
|
|
30
|
+
|
|
31
|
+
<PackageManagerTabs command={{
|
|
32
|
+
npm: "npm install -D babel-jest @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript",
|
|
33
|
+
yarn: "yarn add -D babel-jest @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript",
|
|
34
|
+
pnpm: "pnpm install -D babel-jest @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript"
|
|
35
|
+
}} />
|
|
36
|
+
|
|
37
|
+
### 配置 Jest
|
|
38
|
+
|
|
39
|
+
你需要进一步配置 `jest.config.ts` 文件,以便让 Jest 能够正确地编译和运行测试用例。下面是一个最基本的配置:
|
|
40
|
+
|
|
41
|
+
```ts title="jest.config.ts"
|
|
42
|
+
import type { Config } from 'jest';
|
|
43
|
+
|
|
44
|
+
const config: Config = {
|
|
45
|
+
coverageProvider: 'babel',
|
|
46
|
+
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
|
|
47
|
+
testEnvironment: 'jsdom',
|
|
48
|
+
transform: {
|
|
49
|
+
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
|
|
50
|
+
},
|
|
51
|
+
transformIgnorePatterns: [],
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default config;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
配置中,将 `transformIgnorePatterns` 设置为了空数组,意味着所有的文件都会经过编译,如果你希望提升测试运行的速度,可以按需配置。
|
|
58
|
+
|
|
59
|
+
`setupFilesAfterEnv` 会在启动时执行,在 `jest.setup.ts` 中,可以引入 `@testing-library/jest-dom`。它包含了一组便捷的自定义匹配器,例如 `.toBeInTheDocument()`,使编写测试变得更容易:
|
|
60
|
+
|
|
61
|
+
```ts title="jest.setup.ts"
|
|
62
|
+
import '@testing-library/jest-dom';
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 配置 Babel
|
|
66
|
+
|
|
67
|
+
你需要配置 Babel 让 Jest 能够自动编译 JSX 等语法,下面是一个基本的配置:
|
|
68
|
+
|
|
69
|
+
```js title="babel.config.js"
|
|
70
|
+
module.exports = {
|
|
71
|
+
presets: [
|
|
72
|
+
['@babel/preset-env', { targets: { node: 'current' } }],
|
|
73
|
+
['@babel/preset-react', { runtime: 'automatic' }],
|
|
74
|
+
'@babel/preset-typescript',
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 编写测试用例
|
|
80
|
+
|
|
81
|
+
现在,你可以开始编写测试用了,首先在 `package.json` 中添加一个 `test` 命令:
|
|
82
|
+
|
|
83
|
+
```json title="package.json"
|
|
84
|
+
{
|
|
85
|
+
"scripts": {
|
|
86
|
+
"test": "jest"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
创建一个简单的页面用于测试:
|
|
92
|
+
|
|
93
|
+
```tsx title="routes/page.tsx"
|
|
94
|
+
import { Link } from '@modern-js/runtime/router';
|
|
95
|
+
|
|
96
|
+
const Index = () => (
|
|
97
|
+
<div>
|
|
98
|
+
<h1>Home</h1>
|
|
99
|
+
<Link to="/about">About</Link>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
export default Index;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
添加测试用例,检测页面中是否有预期的文本:
|
|
107
|
+
|
|
108
|
+
```tsx title="__tests__/page.test.tsx"
|
|
109
|
+
import '@testing-library/jest-dom';
|
|
110
|
+
import { render, screen } from '@testing-library/react';
|
|
111
|
+
import { BrowserRouter as Router } from '@modern-js/runtime/router';
|
|
112
|
+
import Page from '../routes/page';
|
|
113
|
+
|
|
114
|
+
describe('Page', () => {
|
|
115
|
+
it('renders a heading', () => {
|
|
116
|
+
render(
|
|
117
|
+
<Router>
|
|
118
|
+
<Page />
|
|
119
|
+
</Router>,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const heading = screen.getByRole('heading', { level: 1 });
|
|
123
|
+
|
|
124
|
+
expect(heading).toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
上述用例中,我们从 `@modern-js/runtime/router` 引入了 `<Router>` 组件,这是因为 React Router 在渲染部分路由相关组件时,必须要有对应的上下文。
|
|
130
|
+
|
|
131
|
+
:::note
|
|
132
|
+
直接在 Modern.js 应用中运行时,`<Router>` 组件会自动注入。
|
|
133
|
+
:::
|
|
134
|
+
|
|
135
|
+
## 运行测试用例
|
|
136
|
+
|
|
137
|
+
执行上述 `test` 命令,运行测试用例:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
PASS src/__tests__/page.test.tsx
|
|
141
|
+
Page
|
|
142
|
+
✓ renders a heading (31 ms)
|
|
143
|
+
|
|
144
|
+
Test Suites: 1 passed, 1 total
|
|
145
|
+
Tests: 1 passed, 1 total
|
|
146
|
+
Snapshots: 0 total
|
|
147
|
+
Time: 0.959 s, estimated 1 s
|
|
148
|
+
```
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Playwright
|
|
2
|
+
|
|
3
|
+
Playwright 是一个测试框架,它允许你使用单一的 API,自动的在 Chromium、Firefox 和 WebKit 环境中运行测试用例,你可以使用它来**编写 E2E 测试**。
|
|
4
|
+
|
|
5
|
+
在 Modern.js 中使用 Playwright 需要先安装依赖,可以执行以下命令:
|
|
6
|
+
|
|
7
|
+
import { PackageManagerTabs } from '@theme';
|
|
8
|
+
|
|
9
|
+
<PackageManagerTabs command={{ npm: "npm init playwright", yarn: "yarn create playwright", pnpm: "pnpm create playwright" }} />
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
上述命令会自动安装 Playwright 依赖,并通过一系列提示帮助你在项目中安装和配置,包括添加一个 `playwright.config.ts` 文件。
|
|
13
|
+
|
|
14
|
+
:::info
|
|
15
|
+
参考 Playwright 官方文档,[安装 Playwright](https://playwright.dev/docs/intro#installation) 查阅更详细的指南。
|
|
16
|
+
:::
|
|
17
|
+
|
|
18
|
+
按照默认配置创建后,可以在项目中看到以下文件:
|
|
19
|
+
|
|
20
|
+
```ts title="tests/example.spec.ts"
|
|
21
|
+
import { test, expect } from '@playwright/test';
|
|
22
|
+
|
|
23
|
+
test('has title', async ({ page }) => {
|
|
24
|
+
await page.goto('https://playwright.dev/');
|
|
25
|
+
|
|
26
|
+
// Expect a title "to contain" a substring.
|
|
27
|
+
await expect(page).toHaveTitle(/Playwright/);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('get started link', async ({ page }) => {
|
|
31
|
+
await page.goto('https://playwright.dev/');
|
|
32
|
+
|
|
33
|
+
// Click the get started link.
|
|
34
|
+
await page.getByRole('link', { name: 'Get started' }).click();
|
|
35
|
+
|
|
36
|
+
// Expects page to have a heading with the name of Installation.
|
|
37
|
+
await expect(
|
|
38
|
+
page.getByRole('heading', { name: 'Installation' }),
|
|
39
|
+
).toBeVisible();
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
这是默认的测试文件,现在创建一些新的页面,并测试它们。
|
|
44
|
+
|
|
45
|
+
## 创建 E2E 测试
|
|
46
|
+
|
|
47
|
+
首先创建两张 Modern.js 的页面。
|
|
48
|
+
|
|
49
|
+
```tsx title="routes/page.tsx"
|
|
50
|
+
import { Link } from '@modern-js/runtime/router';
|
|
51
|
+
|
|
52
|
+
const Index = () => (
|
|
53
|
+
<div>
|
|
54
|
+
<h1>Home</h1>
|
|
55
|
+
<Link to="/about">About</Link>
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export default Index;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```tsx title="routes/about/page.tsx"
|
|
63
|
+
import { Link } from '@modern-js/runtime/router';
|
|
64
|
+
|
|
65
|
+
const Index = () => (
|
|
66
|
+
<div>
|
|
67
|
+
<h1>About</h1>
|
|
68
|
+
<Link to="/">Home</Link>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export default Index;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
接下来,添加测试用例,来保证你页面的链接能够正常工作。
|
|
76
|
+
|
|
77
|
+
```ts title="tests/example.spec.ts"
|
|
78
|
+
import { test, expect } from '@playwright/test'
|
|
79
|
+
|
|
80
|
+
test('should navigate to the about page', async ({ page }) => {
|
|
81
|
+
// Start from the index page (the baseURL is set via the webServer in the playwright.config.ts)
|
|
82
|
+
await page.goto('http://localhost:8080/')
|
|
83
|
+
// Find an element with the text 'About' and click on it
|
|
84
|
+
await page.click('text=About')
|
|
85
|
+
// The new URL should be "/about" (baseURL is used there)
|
|
86
|
+
await expect(page).toHaveURL('http://localhost:8080/about')
|
|
87
|
+
// The new page should contain an h1 with "About"
|
|
88
|
+
await expect(page.locator('h1')).toContainText('About')
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 运行测试用例
|
|
93
|
+
|
|
94
|
+
Playwright 需要你的 Modern.js 服务器保持运行。我们推荐在生产环境产物下运行你的测试用例,你可以执行 `pnpm run build` 和 `pnpm run serve` 在本地模拟生产环境。
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
info Starting production server...
|
|
98
|
+
|
|
99
|
+
> Local: http://localhost:8080/
|
|
100
|
+
> Network: http://10.94.59.30:8080/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
当项目正常构建运行后,可以在另一个终端内执行 `npx playwright test`,运行 Playwright 用例:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
Running 3 tests using 3 workers
|
|
107
|
+
3 passed (2.0s)
|
|
108
|
+
|
|
109
|
+
To open last HTML report run:
|
|
110
|
+
|
|
111
|
+
npx playwright show-report
|
|
112
|
+
```
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Vitest
|
|
2
|
+
|
|
3
|
+
Vitest 是由 Vite 驱动的测试框架,和 React Testing Library 配合可以用于单元测试。
|
|
4
|
+
|
|
5
|
+
在 Modern.js 中使用 Vitest 需要先安装依赖,可以执行以下命令:
|
|
6
|
+
|
|
7
|
+
import { PackageManagerTabs } from '@theme';
|
|
8
|
+
|
|
9
|
+
<PackageManagerTabs command={{
|
|
10
|
+
npm: "npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom",
|
|
11
|
+
yarn: "yarn add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom",
|
|
12
|
+
pnpm: "pnpm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom",
|
|
13
|
+
bun: "bun add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom"
|
|
14
|
+
}} />
|
|
15
|
+
|
|
16
|
+
接下来,你需要创建一个 Vitest 配置文件 `vitest.config.ts`,内容如下:
|
|
17
|
+
|
|
18
|
+
```ts title="vitest.config.ts"
|
|
19
|
+
import { defineConfig } from 'vitest/config'
|
|
20
|
+
import react from '@vitejs/plugin-react'
|
|
21
|
+
|
|
22
|
+
export default defineConfig({
|
|
23
|
+
plugins: [react()],
|
|
24
|
+
test: {
|
|
25
|
+
environment: 'jsdom',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
更多关于 Vitest 配置的信息,可以参考 [Vitest 配置文档](https://vitest.dev/config/#configuration)。
|
|
31
|
+
|
|
32
|
+
你可以选择性的将 `vitest` 命令添加到 `package.json` 中:
|
|
33
|
+
|
|
34
|
+
```json title="package.json"
|
|
35
|
+
{
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "vitest"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
运行该命令后,Vitest 会自动监听你的文件变化,并重新运行用例。
|
|
43
|
+
|
|
44
|
+
## 创建单元测试
|
|
45
|
+
|
|
46
|
+
首先,创建一个简单的页面用于测试:
|
|
47
|
+
|
|
48
|
+
```tsx title="routes/page.tsx"
|
|
49
|
+
import { Link } from '@modern-js/runtime/router';
|
|
50
|
+
|
|
51
|
+
const Index = () => (
|
|
52
|
+
<div>
|
|
53
|
+
<h1>Home</h1>
|
|
54
|
+
<Link to="/about">About</Link>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export default Index;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
添加测试用例,检测页面中是否有预期的文本:
|
|
62
|
+
|
|
63
|
+
```tsx title="__tests__/page.test.tsx"
|
|
64
|
+
import { expect, test } from 'vitest';
|
|
65
|
+
import { render, screen } from '@testing-library/react';
|
|
66
|
+
import { BrowserRouter as Router } from '@modern-js/runtime/router';
|
|
67
|
+
import Page from '../routes/page';
|
|
68
|
+
|
|
69
|
+
test('Page', () => {
|
|
70
|
+
render(
|
|
71
|
+
<Router>
|
|
72
|
+
<Page />
|
|
73
|
+
</Router>,
|
|
74
|
+
);
|
|
75
|
+
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined();
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
上述用例中,我们从 `@modern-js/runtime/router` 引入了 `<Router>` 组件,这是因为 React Router 在渲染部分路由相关组件时,必须要有对应的上下文。
|
|
80
|
+
|
|
81
|
+
:::note
|
|
82
|
+
直接在 Modern.js 应用中运行时,`<Router>` 组件会自动注入。
|
|
83
|
+
:::
|
|
84
|
+
|
|
85
|
+
## 运行测试用例
|
|
86
|
+
|
|
87
|
+
执行上述 `test` 命令,运行测试用例:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
✓ src/__tests__/page.test.tsx (1)
|
|
91
|
+
✓ Page
|
|
92
|
+
|
|
93
|
+
Test Files 1 passed (1)
|
|
94
|
+
Tests 1 passed (1)
|
|
95
|
+
Start at 15:37:12
|
|
96
|
+
Duration 999ms (transform 119ms, setup 0ms, collect 365ms, tests 33ms, environment 421ms, prepare 44ms)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
PASS Waiting for file changes...
|
|
100
|
+
```
|