umi icon indicating copy to clipboard operation
umi copied to clipboard

页面级测试方案

Open sorrycc opened this issue 3 years ago • 8 comments

问题

现在 umi 的测试方案可以做单测和组件测试,但不能做页面级测试。而业务部分又有这方面的稳定性需求。

方案

使用

import Page from 'index.tsx';
import { TestBrowser } from '@umijs/max';

it("test page", () => {
  const html = render(
    <TestBrowser>
      <Page />
    </TestBrowser>
  );
  const logo = html.find("logo");
  expect(logo).tobe(true);
});

实现

1、新增一个 test 插件(preset-umi/src/features/test/test.ts) 2、写文件到 core/testBrowser.tsx 里,export TestBrowser 方法 3、TestBrowser 里的基本思路是

// 初始化 pluginManager
import { createPluginManager } from './plugin';
const pluginManager = createPluginManager();

import { createHistory } from './history';
import { renderClients } from './exports';
export function TestBrowser(props) {
  return renderClients({
    routes: { 'test': { path: '/', files: '', id: 'test' } },
    routeComponents: { 'test': props.children },
    history: createHistory({ type: 'memory', basename: '/', ... }),
  });
}

参考

  • https://github.com/umijs/umi/pull/8493

sorrycc avatar Jul 14 '22 08:07 sorrycc

  • routes 也需要注入一下。layout 的配置有一部分在菜单里面,我需要mock pathname 来让 router 获取到当前路由的layout 配置
  • initalvalues 和 modal 需要提供一个mock的方式来进行数据的更新
  • 额外的一些 utils 要放到哪里?

chenshuai2144 avatar Jul 14 '22 09:07 chenshuai2144

it("test page", () => {
  const modelRef = React.createRef();
  const html = render(
    <TestBrowser modelRef={modelRef}>
      <Page />
    </TestBrowser>
  );
  const logo = html.find("logo");
  expect(logo).tobe(true);

  modelRef.current.initialValues.setInitialValues({ ...newData });
  expect(!!html.find("logo")).tobe(false);
});

我想的操作方式是这样的

chenshuai2144 avatar Jul 14 '22 09:07 chenshuai2144

1、routes 的需求再展开下?注入的是全量路由还是部分路由? 2、感觉可以 3、有哪些额外的 utils,如果不通用就先不放框架里

sorrycc avatar Jul 14 '22 09:07 sorrycc

1、routes 的需求再展开下?注入的是全量路由还是部分路由?

全量的 routes ,比如我在 pathname === "login" 的时候应该菜单不存在,但是在 pathname === "list" 的时候应该要展示。

3、有哪些额外的 utils,如果不通用就先不放框架里

现在想到的有 waitTime, listenRequest (用于判断发起的请求的参数) ,mockRequest(用来mock 返回值)。

类型的话 需要插件的内部类型。

chenshuai2144 avatar Jul 14 '22 09:07 chenshuai2144

全量的 routes ,比如我在 pathname === "login" 的时候应该菜单不存在,但是在 pathname === "list" 的时候应该要展示。

全量路由的话,就基于全量路由做渲染,不需要单独传页面组件,传 url 就好了。

    <TestBrowser location={{ path: '/' }}>
    </TestBrowser>

然后 TestBrowser 实现里的 routes 和 routeComponents 直接从 ./routes 里拿。

sorrycc avatar Jul 14 '22 09:07 sorrycc

能自己注入会方便很多

有一些场景的数据难以mock的时候 可以通过传入props来让逻辑可以走到这一步。

还有复杂的页面有很多子组件的时候 用 url 匹配会比较困难,支持传入可以直接把 这个子页面render出来

routers的主要还是为了菜单

chenshuai2144 avatar Jul 15 '22 07:07 chenshuai2144

页面级测试什么时候可以哈

45010363-koki avatar Aug 08 '22 02:08 45010363-koki

可以看看那个分支的代码,已经跑起来了。

但是有很多细节要做还没有做

chenshuai2144 avatar Aug 08 '22 03:08 chenshuai2144