Browse Source

merge

pull/9795/head
期贤 4 years ago
parent
commit
8adf6dd244
  1. 4
      .github/workflows/ci.yml
  2. 4
      .github/workflows/deploy.yml
  3. 4
      .gitignore
  4. 1
      .husky/.gitignore
  5. 7
      .husky/commit-msg
  6. 4
      .husky/pre-commit
  7. 4
      .stylelintrc.js
  8. 8
      .vscode/extensions.json
  9. 5
      .vscode/settings.json
  10. 2
      Dockerfile
  11. 2
      Dockerfile.dev
  12. 2
      Dockerfile.hub
  13. 2
      README.md
  14. 6
      config/config.ts
  15. 7
      config/proxy.ts
  16. 11
      config/routes.ts
  17. 1
      jest.config.js
  18. 1
      jsconfig.json
  19. 1
      mock/listTableList.ts
  20. 89
      package.json
  21. 22
      playwright.config.ts
  22. 4
      src/access.ts
  23. 37
      src/app.tsx
  24. 4
      src/components/Footer/index.tsx
  25. 2
      src/components/HeaderDropdown/index.less
  26. 2
      src/components/HeaderSearch/index.less
  27. 5
      src/components/HeaderSearch/index.tsx
  28. 2
      src/components/NoticeIcon/NoticeList.less
  29. 4
      src/components/NoticeIcon/index.less
  30. 2
      src/components/NoticeIcon/index.tsx
  31. 4
      src/components/RightContent/AvatarDropdown.tsx
  32. 2
      src/components/RightContent/index.less
  33. 61
      src/e2e/baseLayout.e2e.js
  34. 45
      src/e2e/baseLayout.e2e.spec.ts
  35. 2
      src/global.less
  36. 4
      src/pages/Admin.tsx
  37. 2
      src/pages/Welcome.less
  38. 5
      src/pages/Welcome.tsx
  39. 1
      src/pages/document.ejs
  40. 2
      src/pages/user/Login/index.less
  41. 1
      src/service-worker.js
  42. 41
      tests/PuppeteerEnvironment.js
  43. 39
      tests/beforeTest.js
  44. 45
      tests/getBrowser.js
  45. 7
      tests/run-tests.js
  46. 1
      tsconfig.json

4
.github/workflows/ci.yml

@ -7,7 +7,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
node_version: [12.x, 14.x] node_version: [16.x, 14.x]
os: [ubuntu-latest, windows-latest, macOS-latest] os: [ubuntu-latest, windows-latest, macOS-latest]
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
@ -20,7 +20,7 @@ jobs:
- run: yarn run lint - run: yarn run lint
- run: yarn run tsc - run: yarn run tsc
- run: yarn run build - run: yarn run build
- run: yarn run test:all - run: yarn run test:e2e
env: env:
CI: true CI: true
PROGRESS: none PROGRESS: none

4
.github/workflows/deploy.yml

@ -15,7 +15,7 @@ jobs:
run: yarn run: yarn
- name: plugins - name: plugins
run: yarn add umi-plugin-antd-theme umi-plugin-pro umi-plugin-setting-drawer run: yarn add umi-plugin-pro
- name: fetch-blocks - name: fetch-blocks
run: yarn run pro fetch-blocks run: yarn run pro fetch-blocks
@ -26,6 +26,6 @@ jobs:
- name: Deploy - name: Deploy
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v3
with: with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }} github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist publish_dir: ./dist
force_orphan: true force_orphan: true

4
.gitignore

@ -8,7 +8,6 @@ _roadhog-api-doc
# production # production
/dist /dist
/.vscode
# misc # misc
.DS_Store .DS_Store
@ -19,8 +18,9 @@ yarn-error.log
.idea .idea
yarn.lock yarn.lock
package-lock.json package-lock.json
pnpm-lock.yaml
*bak *bak
.vscode
# visual studio code # visual studio code
.history .history

1
.husky/.gitignore

@ -0,0 +1 @@
_

7
.husky/commit-msg

@ -0,0 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
# Export Git hook params
export GIT_PARAMS=$*
npx --no-install fabric verify-commit

4
.husky/pre-commit

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no-install lint-staged

4
.stylelintrc.js

@ -1,5 +1,3 @@
const fabric = require('@umijs/fabric');
module.exports = { module.exports = {
...fabric.stylelint, extends: [require.resolve('@umijs/fabric/dist/stylelint')],
}; };

8
.vscode/extensions.json

@ -0,0 +1,8 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"stylelint.vscode-stylelint",
"wangzy.sneak-mark"
]
}

5
.vscode/settings.json

@ -0,0 +1,5 @@
{
"editor.formatOnSave": true,
"prettier.requireConfig": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}

2
Dockerfile

@ -7,7 +7,7 @@ RUN yarn
COPY ./ ./ COPY ./ ./
RUN npm run test:all RUN npm run test:e2e
RUN npm run fetch:blocks RUN npm run fetch:blocks

2
Dockerfile.dev

@ -3,7 +3,7 @@ FROM node:latest
WORKDIR /usr/src/app/ WORKDIR /usr/src/app/
COPY package.json ./ COPY package.json ./
RUN npm install --silent --no-cache --registry=https://registry.npm.taobao.org RUN npm install --silent --no-cache --registry=https://registry.npmmirror.com
COPY ./ ./ COPY ./ ./

2
Dockerfile.hub

@ -7,7 +7,7 @@ RUN yarn
COPY ./ ./ COPY ./ ./
RUN npm run test:all RUN npm run test:e2e
RUN npm run fetch:blocks RUN npm run fetch:blocks

2
README.md

@ -6,7 +6,7 @@ Language : 🇺🇸 | [🇨🇳](./README.zh-CN.md) | [🇷🇺](./README.ru-RU.
An out-of-box UI solution for enterprise applications as a React boilerplate. An out-of-box UI solution for enterprise applications as a React boilerplate.
[![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) ![Github Action](https://github.com/ant-design/ant-design-pro/workflows/Node%20CI/badge.svg) ![Deploy](https://github.com/ant-design/ant-design-pro/workflows/Deploy%20CI/badge.svg) [![Dependencies](https://img.shields.io/david/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro) [![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design-pro.svg)](https://david-dm.org/ant-design/ant-design-pro?type=dev) [![Build Status](https://dev.azure.com/ant-design/ant-design-pro/_apis/build/status/ant-design.ant-design-pro?branchName=master)](https://dev.azure.com/ant-design/ant-design-pro/_build/latest?definitionId=1?branchName=master) ![Github Action](https://github.com/ant-design/ant-design-pro/workflows/Node%20CI/badge.svg) ![Deploy](https://github.com/ant-design/ant-design-pro/workflows/Deploy%20CI/badge.svg)
[![Gitter](https://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label) [![Gitter](https://img.shields.io/gitter/room/ant-design/pro-english.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjEyMzUiIGhlaWdodD0iNjUwIiB2aWV3Qm94PSIwIDAgNzQxMCAzOTAwIj4NCjxyZWN0IHdpZHRoPSI3NDEwIiBoZWlnaHQ9IjM5MDAiIGZpbGw9IiNiMjIyMzQiLz4NCjxwYXRoIGQ9Ik0wLDQ1MEg3NDEwbTAsNjAwSDBtMCw2MDBINzQxMG0wLDYwMEgwbTAsNjAwSDc0MTBtMCw2MDBIMCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjMwMCIvPg0KPHJlY3Qgd2lkdGg9IjI5NjQiIGhlaWdodD0iMjEwMCIgZmlsbD0iIzNjM2I2ZSIvPg0KPGcgZmlsbD0iI2ZmZiI%2BDQo8ZyBpZD0iczE4Ij4NCjxnIGlkPSJzOSI%2BDQo8ZyBpZD0iczUiPg0KPGcgaWQ9InM0Ij4NCjxwYXRoIGlkPSJzIiBkPSJNMjQ3LDkwIDMxNy41MzQyMzAsMzA3LjA4MjAzOSAxMzIuODczMjE4LDE3Mi45MTc5NjFIMzYxLjEyNjc4MkwxNzYuNDY1NzcwLDMwNy4wODIwMzl6Ii8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB5PSI0MjAiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHk9Ijg0MCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTI2MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjcyIgeT0iMTY4MCIvPg0KPC9nPg0KPHVzZSB4bGluazpocmVmPSIjczQiIHg9IjI0NyIgeT0iMjEwIi8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzOSIgeD0iNDk0Ii8%2BDQo8L2c%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzMTgiIHg9Ijk4OCIvPg0KPHVzZSB4bGluazpocmVmPSIjczkiIHg9IjE5NzYiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3M1IiB4PSIyNDcwIi8%2BDQo8L2c%2BDQo8L3N2Zz4%3D)](https://gitter.im/ant-design/pro-english?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Join the chat at https://gitter.im/ant-design/ant-design-pro](https://img.shields.io/gitter/room/ant-design/ant-design-pro.svg?style=flat-square&logoWidth=20&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgd2lkdGg9IjkwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAzMCAyMCI%2BDQo8ZGVmcz4NCjxwYXRoIGlkPSJzIiBkPSJNMCwtMSAwLjU4Nzc4NSwwLjgwOTAxNyAtMC45NTEwNTcsLTAuMzA5MDE3SDAuOTUxMDU3TC0wLjU4Nzc4NSwwLjgwOTAxN3oiIGZpbGw9IiNmZmRlMDAiLz4NCjwvZGVmcz4NCjxyZWN0IHdpZHRoPSIzMCIgaGVpZ2h0PSIyMCIgZmlsbD0iI2RlMjkxMCIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1KSBzY2FsZSgzKSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsMikgcm90YXRlKDIzLjAzNjI0MykiLz4NCjx1c2UgeGxpbms6aHJlZj0iI3MiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyLDQpIHJvdGF0ZSg0NS44Njk4OTgpIi8%2BDQo8dXNlIHhsaW5rOmhyZWY9IiNzIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMiw3KSByb3RhdGUoNjkuOTQ1Mzk2KSIvPg0KPHVzZSB4bGluazpocmVmPSIjcyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAsOSkgcm90YXRlKDIwLjY1OTgwOCkiLz4NCjwvc3ZnPg%3D%3D)](https://gitter.im/ant-design/ant-design-pro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build With Umi](https://img.shields.io/badge/build%20with-umi-028fe4.svg?style=flat-square)](http://umijs.org/) ![](https://badgen.net/badge/icon/Ant%20Design?icon=https://gw.alipayobjects.com/zos/antfincdn/Pp4WPgVDB3/KDpgvguMpGfqaHPjicRK.svg&label)

6
config/config.ts

@ -316,9 +316,13 @@ export default defineConfig({
component: '404', component: '404',
}, },
], ],
access: {},
// Theme for antd: https://ant.design/docs/react/customize-theme-cn // Theme for antd: https://ant.design/docs/react/customize-theme-cn
theme: { theme: {
'primary-color': defaultSettings.primaryColor, // 如果不想要 configProvide 动态设置主题需要把这个设置为 default
// 只有设置为 variable, 才能使用 configProvide 动态设置主色调
// https://ant.design/docs/react/customize-theme-variable-cn
'root-entry-name': 'variable',
}, },
// esbuild is father build tools // esbuild is father build tools
// https://umijs.org/plugins/plugin-esbuild // https://umijs.org/plugins/plugin-esbuild

7
config/proxy.ts

@ -8,15 +8,18 @@
*/ */
export default { export default {
dev: { dev: {
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
'/api/': { '/api/': {
// 要代理的地址
target: 'https://preview.pro.ant.design', target: 'https://preview.pro.ant.design',
// 配置了这个可以从 http 代理到 https
// 依赖 origin 的功能可能需要这个,比如 cookie
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^': '' },
}, },
}, },
test: { test: {
'/api/': { '/api/': {
target: 'https://preview.pro.ant.design', target: 'https://proapi.azurewebsites.net',
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^': '' }, pathRewrite: { '^': '' },
}, },

11
config/routes.ts

@ -4,14 +4,9 @@
layout: false, layout: false,
routes: [ routes: [
{ {
path: '/user', name: 'login',
routes: [ path: '/user/login',
{ component: './user/Login',
name: 'login',
path: '/user/login',
component: './user/Login',
},
],
}, },
{ {
component: './404', component: './404',

1
jest.config.js

@ -1,6 +1,5 @@
module.exports = { module.exports = {
testURL: 'http://localhost:8000', testURL: 'http://localhost:8000',
testEnvironment: './tests/PuppeteerEnvironment',
verbose: false, verbose: false,
extraSetupFiles: ['./tests/setupTests.js'], extraSetupFiles: ['./tests/setupTests.js'],
globals: { globals: {

1
jsconfig.json

@ -1,5 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"jsx": "react-jsx",
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"baseUrl": ".", "baseUrl": ".",

1
mock/listTableList.ts

@ -1,4 +1,3 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import moment from 'moment'; import moment from 'moment';
import { parse } from 'url'; import { parse } from 'url';

89
package.json

@ -1,6 +1,6 @@
{ {
"name": "ant-design-pro", "name": "ant-design-pro",
"version": "5.0.0", "version": "5.2.0",
"private": true, "private": true,
"description": "An out-of-box UI solution for enterprise applications", "description": "An out-of-box UI solution for enterprise applications",
"scripts": { "scripts": {
@ -26,19 +26,19 @@
"lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto", "lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less", "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"openapi": "umi openapi", "openapi": "umi openapi",
"precommit": "lint-staged", "playwright": "playwright install && playwright test",
"prepare": "husky install",
"prettier": "prettier -c --write \"src/**/*\"", "prettier": "prettier -c --write \"src/**/*\"",
"serve": "umi-serve",
"start": "cross-env UMI_ENV=dev umi dev", "start": "cross-env UMI_ENV=dev umi dev",
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev", "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev",
"start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev", "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev",
"start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev", "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev",
"start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev", "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev",
"start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev", "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev",
"pretest": "node ./tests/beforeTest",
"test": "umi test", "test": "umi test",
"test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components", "test:component": "umi test ./src/components",
"serve": "umi-serve", "test:e2e": "node ./tests/run-tests.js",
"tsc": "tsc --noEmit" "tsc": "tsc --noEmit"
}, },
"lint-staged": { "lint-staged": {
@ -55,73 +55,75 @@
], ],
"dependencies": { "dependencies": {
"@ant-design/charts": "^0.9.4", "@ant-design/charts": "^0.9.4",
"@ant-design/icons": "^4.5.0", "@ant-design/icons": "^4.7.0",
"@ant-design/pro-descriptions": "^1.6.8", "@ant-design/pro-card": "^1.19.0",
"@ant-design/pro-form": "^1.18.3", "@ant-design/pro-descriptions": "^1.10.0",
"@ant-design/pro-layout": "^6.15.3", "@ant-design/pro-form": "^1.64.0",
"@ant-design/pro-table": "^2.30.8", "@ant-design/pro-layout": "^6.35.0",
"@ant-design/pro-table": "^2.71.0",
"@antv/data-set": "^0.11.0", "@antv/data-set": "^0.11.0",
"@antv/l7": "^2.3.7", "@antv/l7": "^2.3.7",
"@antv/l7-maps": "^2.3.7", "@antv/l7-maps": "^2.3.7",
"@antv/l7-react": "^2.1.9", "@antv/l7-react": "^2.1.9",
"@umijs/route-utils": "^1.0.36", "@umijs/route-utils": "^2.0.0",
"ahooks": "^2.0.0", "ahooks": "^2.0.0",
"antd": "^4.14.0", "antd": "^4.19.0",
"bizcharts": "^3.5.3-beta.0", "bizcharts": "^3.5.3-beta.0",
"bizcharts-plugin-slider": "^2.1.1-beta.1", "bizcharts-plugin-slider": "^2.1.1-beta.1",
"classnames": "^2.2.6", "classnames": "^2.3.0",
"gg-editor": "^2.0.2", "gg-editor": "^2.0.2",
"lodash": "^4.17.11", "lodash": "^4.17.0",
"lodash-decorators": "^6.0.0", "lodash-decorators": "^6.0.0",
"moment": "^2.25.3", "moment": "^2.29.0",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"nzh": "^1.0.3", "nzh": "^1.0.3",
"omit.js": "^2.0.2", "omit.js": "^2.0.2",
"rc-menu": "^9.1.0",
"rc-util": "^5.16.0",
"react": "^17.0.0", "react": "^17.0.0",
"react-dev-inspector": "^1.1.1", "react-dev-inspector": "^1.7.0",
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-fittext": "^1.0.0", "react-fittext": "^1.0.0",
"react-helmet-async": "^1.0.4", "react-helmet-async": "^1.2.0",
"react-router": "^4.3.1", "react-router": "^4.3.1",
"umi": "^3.5.0", "umi": "^3.5.0",
"umi-serve": "^1.9.10" "umi-serve": "^1.9.10"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^2.0.2", "@ant-design/pro-cli": "^2.1.0",
"@playwright/test": "^1.17.0",
"@types/express": "^4.17.0", "@types/express": "^4.17.0",
"@types/history": "^4.7.2", "@types/history": "^4.7.0",
"@types/jest": "^26.0.0", "@types/jest": "^26.0.0",
"@types/lodash": "^4.14.144", "@types/lodash": "^4.14.0",
"@types/react": "^17.0.0", "@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0", "@types/react-dom": "^17.0.0",
"@types/react-helmet": "^6.1.0", "@types/react-helmet": "^6.1.0",
"@umijs/fabric": "^2.6.2", "@umijs/fabric": "^2.8.0",
"@umijs/openapi": "^1.1.14", "@umijs/openapi": "^1.3.0",
"@umijs/plugin-blocks": "^2.0.5", "@umijs/plugin-blocks": "^2.2.0",
"@umijs/plugin-esbuild": "^1.0.1", "@umijs/plugin-esbuild": "^1.4.0",
"@umijs/plugin-openapi": "^1.2.0", "@umijs/plugin-openapi": "^1.3.0",
"@umijs/preset-ant-design-pro": "^1.2.0", "@umijs/preset-ant-design-pro": "^1.3.0",
"@umijs/preset-dumi": "^1.1.7", "@umijs/preset-dumi": "^1.1.0",
"@umijs/preset-react": "^1.8.17", "@umijs/preset-react": "^2.1.0",
"@umijs/yorkie": "^2.0.3",
"carlo": "^0.9.46",
"cross-env": "^7.0.0", "cross-env": "^7.0.0",
"cross-port-killer": "^1.1.1", "cross-port-killer": "^1.3.0",
"detect-installer": "^1.0.1", "detect-installer": "^1.0.0",
"enzyme": "^3.11.0", "eslint": "^7.32.0",
"eslint": "^7.1.0", "gh-pages": "^3.2.0",
"express": "^4.17.1", "husky": "^7.0.4",
"gh-pages": "^3.0.0", "jsdom-global": "^3.0.0",
"jsdom-global": "^3.0.2",
"lint-staged": "^10.0.0", "lint-staged": "^10.0.0",
"mockjs": "^1.0.1-beta3", "mockjs": "^1.1.0",
"prettier": "^2.3.2", "prettier": "^2.5.0",
"puppeteer-core": "^8.0.0",
"stylelint": "^13.0.0", "stylelint": "^13.0.0",
"typescript": "^4.2.2" "swagger-ui-react": "^3.52.0",
"typescript": "^4.5.0",
"umi-serve": "^1.9.10"
}, },
"engines": { "engines": {
"node": ">=10.0.0" "node": ">=12.0.0"
}, },
"create-umi": { "create-umi": {
"ignoreScript": [ "ignoreScript": [
@ -151,8 +153,5 @@
"CNAME", "CNAME",
"create-umi" "create-umi"
] ]
},
"gitHooks": {
"commit-msg": "fabric verify-commit"
} }
} }

22
playwright.config.ts

@ -0,0 +1,22 @@
// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';
import { devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
use: {
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
],
};
export default config;

4
src/access.ts

@ -1,8 +1,8 @@
/** /**
* @see https://umijs.org/zh-CN/plugins/plugin-access * @see https://umijs.org/zh-CN/plugins/plugin-access
* */ * */
export default function access(initialState: { currentUser?: API.CurrentUser | undefined }) { export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
const { currentUser } = initialState || {}; const { currentUser } = initialState ?? {};
return { return {
canAdmin: currentUser && currentUser.access === 'admin', canAdmin: currentUser && currentUser.access === 'admin',
}; };

37
src/app.tsx

@ -1,4 +1,5 @@
import type { Settings as LayoutSettings } from '@ant-design/pro-layout'; import type { Settings as LayoutSettings } from '@ant-design/pro-layout';
import { SettingDrawer } from '@ant-design/pro-layout';
import { PageLoading } from '@ant-design/pro-layout'; import { PageLoading } from '@ant-design/pro-layout';
import type { RunTimeLayoutConfig } from 'umi'; import type { RunTimeLayoutConfig } from 'umi';
import { history, Link } from 'umi'; import { history, Link } from 'umi';
@ -6,6 +7,7 @@ import RightContent from '@/components/RightContent';
import Footer from '@/components/Footer'; import Footer from '@/components/Footer';
import { currentUser as queryCurrentUser } from './services/ant-design-pro/api'; import { currentUser as queryCurrentUser } from './services/ant-design-pro/api';
import { BookOutlined, LinkOutlined } from '@ant-design/icons'; import { BookOutlined, LinkOutlined } from '@ant-design/icons';
import defaultSettings from '../config/defaultSettings';
const isDev = process.env.NODE_ENV === 'development'; const isDev = process.env.NODE_ENV === 'development';
const loginPath = '/user/login'; const loginPath = '/user/login';
@ -21,6 +23,7 @@ export const initialStateConfig = {
export async function getInitialState(): Promise<{ export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>; settings?: Partial<LayoutSettings>;
currentUser?: API.CurrentUser; currentUser?: API.CurrentUser;
loading?: boolean;
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>; fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
}> { }> {
const fetchUserInfo = async () => { const fetchUserInfo = async () => {
@ -32,23 +35,23 @@ export async function getInitialState(): Promise<{
} }
return undefined; return undefined;
}; };
// 如果是登录页面,执行 // 如果是登录页面,执行
if (history.location.pathname !== loginPath) { if (history.location.pathname !== loginPath) {
const currentUser = await fetchUserInfo(); const currentUser = await fetchUserInfo();
return { return {
fetchUserInfo, fetchUserInfo,
currentUser, currentUser,
settings: {}, settings: defaultSettings,
}; };
} }
return { return {
fetchUserInfo, fetchUserInfo,
settings: {}, settings: defaultSettings,
}; };
} }
// ProLayout 支持的api https://procomponents.ant.design/components/layout // ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState }) => { export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return { return {
rightContentRender: () => <RightContent />, rightContentRender: () => <RightContent />,
disableContentMargin: false, disableContentMargin: false,
@ -65,11 +68,11 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
}, },
links: isDev links: isDev
? [ ? [
<Link to="/umi/plugin/openapi" target="_blank"> <Link key="openapi" to="/umi/plugin/openapi" target="_blank">
<LinkOutlined /> <LinkOutlined />
<span>OpenAPI </span> <span>OpenAPI </span>
</Link>, </Link>,
<Link to="/~docs"> <Link to="/~docs" key="docs">
<BookOutlined /> <BookOutlined />
<span></span> <span></span>
</Link>, </Link>,
@ -78,6 +81,28 @@ export const layout: RunTimeLayoutConfig = ({ initialState }) => {
menuHeaderRender: undefined, menuHeaderRender: undefined,
// 自定义 403 页面 // 自定义 403 页面
// unAccessible: <div>unAccessible</div>, // unAccessible: <div>unAccessible</div>,
// 增加一个 loading 的状态
childrenRender: (children, props) => {
// if (initialState?.loading) return <PageLoading />;
return (
<>
{children}
{!props.location?.pathname?.includes('/login') && (
<SettingDrawer
disableUrlParams
enableDarkTheme
settings={initialState?.settings}
onSettingChange={(settings) => {
setInitialState((preInitialState) => ({
...preInitialState,
settings,
}));
}}
/>
)}
</>
);
},
...initialState?.settings, ...initialState?.settings,
}; };
}; };

4
src/components/Footer/index.tsx

@ -2,7 +2,7 @@ import { useIntl } from 'umi';
import { GithubOutlined } from '@ant-design/icons'; import { GithubOutlined } from '@ant-design/icons';
import { DefaultFooter } from '@ant-design/pro-layout'; import { DefaultFooter } from '@ant-design/pro-layout';
export default () => { const Footer: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
const defaultMessage = intl.formatMessage({ const defaultMessage = intl.formatMessage({
id: 'app.copyright.produced', id: 'app.copyright.produced',
@ -37,3 +37,5 @@ export default () => {
/> />
); );
}; };
export default Footer;

2
src/components/HeaderDropdown/index.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.container > * { .container > * {
background-color: @popover-bg; background-color: @popover-bg;

2
src/components/HeaderSearch/index.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.headerSearch { .headerSearch {
display: inline-flex; display: inline-flex;

5
src/components/HeaderSearch/index.tsx

@ -1,4 +1,5 @@
import { SearchOutlined } from '@ant-design/icons'; import { SearchOutlined } from '@ant-design/icons';
import type { InputRef } from 'antd';
import { AutoComplete, Input } from 'antd'; import { AutoComplete, Input } from 'antd';
import useMergedState from 'rc-util/es/hooks/useMergedState'; import useMergedState from 'rc-util/es/hooks/useMergedState';
import type { AutoCompleteProps } from 'antd/es/auto-complete'; import type { AutoCompleteProps } from 'antd/es/auto-complete';
@ -31,7 +32,7 @@ const HeaderSearch: React.FC<HeaderSearchProps> = (props) => {
...restProps ...restProps
} = props; } = props;
const inputRef = useRef<Input | null>(null); const inputRef = useRef<InputRef | null>(null);
const [value, setValue] = useMergedState<string | undefined>(defaultValue, { const [value, setValue] = useMergedState<string | undefined>(defaultValue, {
value: props.value, value: props.value,
@ -74,7 +75,7 @@ const HeaderSearch: React.FC<HeaderSearchProps> = (props) => {
className={inputClass} className={inputClass}
value={value} value={value}
options={restProps.options} options={restProps.options}
onChange={setValue} onChange={(completeValue) => setValue(completeValue)}
> >
<Input <Input
size="small" size="small"

2
src/components/NoticeIcon/NoticeList.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.list { .list {
max-height: 400px; max-height: 400px;

4
src/components/NoticeIcon/index.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.popover { .popover {
position: relative; position: relative;
@ -28,7 +28,7 @@
.ant-tabs-nav-scroll { .ant-tabs-nav-scroll {
text-align: center; text-align: center;
} }
.ant-tabs-bar { .ant-tabs-nav {
margin-bottom: 0; margin-bottom: 0;
} }
} }

2
src/components/NoticeIcon/index.tsx

@ -70,7 +70,7 @@ const getUnreadData = (noticeData: Record<string, API.NoticeIconItem[]>) => {
return unreadMsg; return unreadMsg;
}; };
const NoticeIconView = () => { const NoticeIconView: React.FC = () => {
const { initialState } = useModel('@@initialState'); const { initialState } = useModel('@@initialState');
const { currentUser } = initialState || {}; const { currentUser } = initialState || {};
const [notices, setNotices] = useState<API.NoticeIconItem[]>([]); const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);

4
src/components/RightContent/AvatarDropdown.tsx

@ -17,14 +17,14 @@ export type GlobalHeaderRightProps = {
*/ */
const loginOut = async () => { const loginOut = async () => {
await outLogin(); await outLogin();
const { query = {}, pathname } = history.location; const { query = {}, search, pathname } = history.location;
const { redirect } = query; const { redirect } = query;
// Note: There may be security issues, please note // Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) { if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({ history.replace({
pathname: '/user/login', pathname: '/user/login',
search: stringify({ search: stringify({
redirect: pathname, redirect: pathname + search,
}), }),
}); });
} }

2
src/components/RightContent/index.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
@pro-header-hover-bg: rgba(0, 0, 0, 0.025); @pro-header-hover-bg: rgba(0, 0, 0, 0.025);

61
src/e2e/baseLayout.e2e.js

@ -1,61 +0,0 @@
const { uniq } = require('lodash');
const RouterConfig = require('../../config/config').default.routes;
const BASE_URL = `http://localhost:${process.env.PORT || 8001}`;
function formatter(routes, parentPath = '') {
const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
let result = [];
routes.forEach((item) => {
if (item.path && !item.path.startsWith('/')) {
result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
}
if (item.path && item.path.startsWith('/')) {
result.push(`${item.path}`.replace(/\/{1,}/g, '/'));
}
if (item.routes) {
result = result.concat(
formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
);
}
});
return uniq(result.filter((item) => !!item));
}
beforeEach(async () => {
await page.goto(`${BASE_URL}`);
await page.evaluate(() => {
localStorage.setItem('antd-pro-authority', '["admin"]');
});
});
describe('Ant Design Pro E2E test', () => {
const testPage = (path) => async () => {
await page.goto(`${BASE_URL}${path}`);
await page.waitForSelector('footer', {
timeout: 2000,
});
const haveFooter = await page.evaluate(
() => document.getElementsByTagName('footer').length > 0,
);
expect(haveFooter).toBeTruthy();
};
const routers = formatter(RouterConfig);
routers.forEach((route) => {
it(`test pages ${route}`, testPage(route));
});
it('topmenu should have footer', async () => {
const params = '?navTheme=light&layout=topmenu';
await page.goto(`${BASE_URL}${params}`);
await page.waitForSelector('footer', {
timeout: 2000,
});
const haveFooter = await page.evaluate(
() => document.getElementsByTagName('footer').length > 0,
);
expect(haveFooter).toBeTruthy();
});
});

45
src/e2e/baseLayout.e2e.spec.ts

@ -0,0 +1,45 @@
import type { Page } from '@playwright/test';
import { test, expect } from '@playwright/test';
const { uniq } = require('lodash');
const RouterConfig = require('../../config/routes').default;
const BASE_URL = `http://localhost:${process.env.PORT || 8001}`;
function formatter(routes: any, parentPath = ''): string[] {
const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
let result: string[] = [];
routes.forEach((item: { path: string; routes: string }) => {
if (item.path && !item.path.startsWith('/')) {
result.push(`${fixedParentPath}/${item.path}`.replace(/\/{1,}/g, '/'));
}
if (item.path && item.path.startsWith('/')) {
result.push(`${item.path}`.replace(/\/{1,}/g, '/'));
}
if (item.routes) {
result = result.concat(
formatter(item.routes, item.path ? `${fixedParentPath}/${item.path}` : parentPath),
);
}
});
return uniq(result.filter((item) => !!item));
}
const testPage = (path: string, page: Page) => async () => {
await page.evaluate(() => {
localStorage.setItem('antd-pro-authority', '["admin"]');
});
await page.goto(`${BASE_URL}${path}`);
await page.waitForSelector('footer', {
timeout: 2000,
});
const haveFooter = await page.evaluate(() => document.getElementsByTagName('footer').length > 0);
expect(haveFooter).toBeTruthy();
};
const routers = formatter(RouterConfig);
routers.forEach((route) => {
test(`test route page ${route}`, async ({ page }) => {
await testPage(route, page);
});
});

2
src/global.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import '~antd/es/style/variable.less';
html, html,
body, body,

4
src/pages/Admin.tsx

@ -4,7 +4,7 @@ import { Card, Typography, Alert } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout'; import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { useIntl } from 'umi'; import { useIntl } from 'umi';
export default (): React.ReactNode => { const Admin: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
return ( return (
<PageHeaderWrapper <PageHeaderWrapper
@ -41,3 +41,5 @@ export default (): React.ReactNode => {
</PageHeaderWrapper> </PageHeaderWrapper>
); );
}; };
export default Admin;

2
src/pages/Welcome.less

@ -1,4 +1,4 @@
@import '~antd/lib/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.pre { .pre {
margin: 12px 0; margin: 12px 0;

5
src/pages/Welcome.tsx

@ -12,8 +12,9 @@ const CodePreview: React.FC = ({ children }) => (
</pre> </pre>
); );
export default (): React.ReactNode => { const Welcome: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
return ( return (
<PageContainer> <PageContainer>
<Card> <Card>
@ -61,3 +62,5 @@ export default (): React.ReactNode => {
</PageContainer> </PageContainer>
); );
}; };
export default Welcome;

1
src/pages/document.ejs

@ -2,6 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="theme-color" content="#1890ff" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta <meta
name="keywords" name="keywords"

2
src/pages/user/Login/index.less

@ -1,4 +1,4 @@
@import '~antd/es/style/themes/default.less'; @import (reference) '~antd/es/style/themes/index';
.container { .container {
display: flex; display: flex;

1
src/service-worker.js

@ -1,4 +1,3 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable no-restricted-globals */ /* eslint-disable no-restricted-globals */
/* eslint-disable no-underscore-dangle */ /* eslint-disable no-underscore-dangle */
/* globals workbox */ /* globals workbox */

41
tests/PuppeteerEnvironment.js

@ -1,41 +0,0 @@
// eslint-disable-next-line
const NodeEnvironment = require('jest-environment-node');
const getBrowser = require('./getBrowser');
class PuppeteerEnvironment extends NodeEnvironment {
// Jest is not available here, so we have to reverse engineer
// the setTimeout function, see https://github.com/facebook/jest/blob/v23.1.0/packages/jest-runtime/src/index.js#L823
setTimeout(timeout) {
if (this.global.jasmine) {
// eslint-disable-next-line no-underscore-dangle
this.global.jasmine.DEFAULT_TIMEOUT_INTERVAL = timeout;
} else {
this.global[Symbol.for('TEST_TIMEOUT_SYMBOL')] = timeout;
}
}
async setup() {
const browser = await getBrowser();
const page = await browser.newPage();
this.global.browser = browser;
this.global.page = page;
}
async teardown() {
const { page, browser } = this.global;
if (page) {
await page.close();
}
if (browser) {
await browser.disconnect();
}
if (browser) {
await browser.close();
}
}
}
module.exports = PuppeteerEnvironment;

39
tests/beforeTest.js

@ -1,39 +0,0 @@
/* eslint-disable global-require */
/* eslint-disable import/no-extraneous-dependencies */
const { execSync } = require('child_process');
const { join } = require('path');
const findChrome = require('carlo/lib/find_chrome');
const detectInstaller = require('detect-installer');
const installPuppeteer = () => {
// find can use package manager
const packages = detectInstaller(join(__dirname, '../'));
// get installed package manager
const packageName = packages.find(detectInstaller.hasPackageCommand) || 'npm';
console.log(`🤖 will use ${packageName} install puppeteer`);
const command = `${packageName} ${packageName.includes('yarn') ? 'add' : 'i'} puppeteer`;
execSync(command, {
stdio: 'inherit',
});
};
const initPuppeteer = async () => {
try {
// eslint-disable-next-line import/no-unresolved
const findChromePath = await findChrome({});
const { executablePath } = findChromePath;
console.log(`🧲 find you browser in ${executablePath}`);
return;
} catch (error) {
console.log('🧲 no find chrome');
}
try {
require.resolve('puppeteer');
} catch (error) {
// need install puppeteer
await installPuppeteer();
}
};
initPuppeteer();

45
tests/getBrowser.js

@ -1,45 +0,0 @@
/* eslint-disable global-require */
/* eslint-disable import/no-extraneous-dependencies */
const findChrome = require('carlo/lib/find_chrome');
const getBrowser = async () => {
try {
// eslint-disable-next-line import/no-unresolved
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--no-first-run',
'--no-zygote',
'--no-sandbox',
],
});
return browser;
} catch (error) {
// console.log(error)
}
try {
// eslint-disable-next-line import/no-unresolved
const puppeteer = require('puppeteer-core');
const findChromePath = await findChrome({});
const { executablePath } = findChromePath;
const browser = await puppeteer.launch({
executablePath,
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--no-first-run',
'--no-zygote',
'--no-sandbox',
],
});
return browser;
} catch (error) {
console.log('🧲 no find chrome');
}
throw new Error('no find puppeteer');
};
module.exports = getBrowser;

7
tests/run-tests.js

@ -1,8 +1,5 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable eslint-comments/no-unlimited-disable */
const { spawn } = require('child_process'); const { spawn } = require('child_process');
// eslint-disable-next-line import/no-extraneous-dependencies
const { kill } = require('cross-port-killer'); const { kill } = require('cross-port-killer');
const env = Object.create(process.env); const env = Object.create(process.env);
@ -36,13 +33,13 @@ startServer.stdout.on('data', (data) => {
console.log('Development server is started, ready to run tests.'); console.log('Development server is started, ready to run tests.');
const testCmd = spawn( const testCmd = spawn(
/^win/.test(process.platform) ? 'npm.cmd' : 'npm', /^win/.test(process.platform) ? 'npm.cmd' : 'npm',
['test', '--', '--maxWorkers=1', '--runInBand'], ['run', 'playwright'],
{ {
stdio: 'inherit', stdio: 'inherit',
}, },
); );
testCmd.on('exit', (code) => { testCmd.on('exit', (code) => {
console.log(code); console.log('服务已经退出,退出码:', code);
startServer.kill(); startServer.kill();
process.exit(code); process.exit(code);
}); });

1
tsconfig.json

@ -26,6 +26,7 @@
"include": [ "include": [
"mock/**/*", "mock/**/*",
"src/**/*", "src/**/*",
"playwright.config.ts",
"tests/**/*", "tests/**/*",
"test/**/*", "test/**/*",
"__test__/**/*", "__test__/**/*",

Loading…
Cancel
Save