关于vue.js:自动化回归测试平台-AREX-前端架构演变史-Tabs-动态组件设计

47次阅读

共计 5161 个字符,预计需要花费 13 分钟才能阅读完成。

AREX(http://arextest.com/)是一款开源的基于实在申请与数据的自动化回归测试平台,利用 Java Agent 技术与比对技术,通过流量录制回放能力实现疾速无效的回归测试。同时提供了接口测试、接口比对测试等丰盛的自动化测试性能。

在这个系列中,咱们将会介绍 AREX 前端架构的演变过程,以及在演变过程中遇到的问题和解决方案,一来作为开发过程的教训分享,二来不便大家对 AREX 源码的了解以及二次开发。

Tabs 动静组件设计

Tabs organize content across different screens, data sets, and other interactions —— Material Design

Tab 组件在前端开发中有着宽泛的利用场景,它可能满足各种不同的需要,如数据展现、导航菜单、表单填写、产品分类、菜单展现、图片幻灯片等多种场景。在 AREX 中也有大量应用 Tabs 组件的场景,其中最具代表性的是 AREX 主工作区。在这篇文章中,我将会介绍 AREX 主工作区中 Tabs 动静组件的设计思路和实现迭代过程。

主工作区是 AREX 的外围性能区域,用户在这里实现 API 调试、录制用例回放、环境治理、利用配置等一系列工作。因为提供的性能泛滥,用户应用流程非线性,常常须要在多个功能模块之间切换,为了提供良好的用户体验和高效的操作形式,AREX 主工作区采纳了 Tab 组件来组织和展现主工作区的不同性能页面模块。

用户在主工作区借助 Tabs 疾速地切换到所需的性能页面,同时 Tabs 在切换时对性能页面进行缓存,防止了频繁地从新初始化性能页面的操作,进步了用户的体验和应用效率。这看起来是一个理所应当且很简略的性能,毕竟 Tabs 自身的性能已在 UI 框架中实现,然而在理论的过程中还是碰到了一些问题。

1.0 —— 原始的条件渲染

在 AREX 的晚期版本中,Tabs 组件采纳的是 Ant Design 4.23.0 之前的 JSX 拼接写法。Tabs 组件实现的简化代码如下:

<Tabs
activeKey={activePane}
onEdit={handleTabsEdit}
onChange={setActivePane}
>
{panes.map((pane) => (
<Tabs.TabPane
key={pane.key}
tab={genTabTitle(pane)}
>
{pane.paneType === PaneTypeEnum.Replay && (<Replay data={pane.data as ApplicationDataType} />
)}
{pane.paneType === PaneTypeEnum.ReplayCase && (<ReplayCase data={pane.data as PlanItemStatistics} />
)}
</Tabs.TabPane>
))}
</Tabs>

主工作区中的 panes 负责保护各个性能页面的品种、名称、页面初始化参数等数据,并由全局状态进行治理。当新增或敞开性能页面时,触发 panes 的更新操作。

主工作区的 Tabs.TabPane 组件通过条件渲染来实现。在对 panes 进行遍历时,依据每个 pane 的 paneType 属性匹配到相应的页面组件,并进行渲染。这种实现形式的长处在于简略间接,通过条件判断可能实现页面的动静渲染。然而,这种形式也存在一些毛病,例如大量的条件判断语句升高了代码的可读性和优雅性。同时,可扩展性也较差,当须要新增一个性能页面时,须要批改 Tabs 组件的代码,违反了开闭准则。

因而,为了解决这些问题,咱们自然而然地想到须要一种更加通用的实现形式,以适配将来可能呈现的更多未知的性能页面。

2.0 —— 动静组件渲染

因为 Tabs 组件中 TabPane 所对应的理论组件是不确定的,它随着用户的操作而 动静 变动,因而咱们想到将 TabPane 由原先的条件渲染组件改为动静组件。通过动静组件的形式,咱们能够依据配置信息动静地加载和渲染性能页面,实现了更高的可扩展性和灵活性。这样一来,新增性能页面时只需配置相应的参数,而无需批改 Tabs 组件的代码,大大减少了保护和扩大的老本。这种改良不仅晋升了代码的可读性和优雅性,也为将来的性能扩大奠定了松软的根底。

在前端开发中,动静组件是一种广泛应用的技术,它能够帮忙咱们实现高度灵便和可复用的组件,并满足动静渲染组件的需要。动静组件的概念是基于组件化开发的理念,将页面拆分为独立的可重用单元,通过动静加载和渲染这些组件,实现灵便的页面构建和交互。

在 Vue 框架中,咱们能够通过 <component v-bind:is="componentName"></component> 的形式来实现动静组件。其中,componentName 能够是一个变量,依据须要动静指定不同的组件名称,从而实现组件的动静加载和渲染。

而在 React 框架中,咱们能够通过申明一个组件的变量,而后将这个变量作为 JSX 的标签名来实现动静组件。这种形式容许咱们依据须要在运行时抉择不同的组件进行渲染。此外,咱们还能够应用 React.createElement() 办法来动态创建并渲染组件。

在 AREX 降级适配 Ant Design 5.0 的重构版本中,咱们应用了第二种形式来实现动静组件,同时应用了 Ant Design 提供的新的 Tabs 简写形式,用 item 有更好的性能和更不便的数据组织形式。优化后的动静 Tabs 组件的简化代码如下:

// Panes.ts
const CommonPanes = {
ReplayPane,
ReplayCasePane,
};
const ExtraPanes = {}; // 对外裸露的扩大配置
const Panes = Object.assign(CommonPanes, ExtraPanes);
export default Panes
// Layout.tsx
const tabsItems = useMemo(() =>
panes.map((pane) => {const Pane = Panes[pane.paneType];
return {
key: pane.key,
label: genTabTitle(pane),
children: <ErrorBoundary>{React.createElement(Pane, { data: pane})}</ErrorBoundary>,
};
}),
[panes],
);
<Tabs
items={tabsItems}
activeKey={activePane}
onEdit={handleTabsEdit}
onChange={setActivePane}
/>

在这个计划中,咱们将性能页面的品种和组件映射逻辑从 Tabs 组件中抽离进去,放到了一个独自的文件中,这样做的益处是将 Tabs 组件的职责进行了拆分,使得 Tabs 组件外部不再关注具体被注册的性能页面组件,同时也不便了性能页面的扩大。

除此之外还有两个细节该当留神,其一是在 Panes.ts 中定义了 ExtraPanes 对象,用于对外裸露扩大组件的配置,供对该项目标二次开发者应用,提供专用的配置空间能够实现二次开发代码与源代码的隔离,避免二次开发在与源代码同步时产生代码抵触,这样的配置空间隔离在 AREX 的设计中也有多处体现;其二是在动静组件外应用了 ErrorBoundary 组件对其包裹,用于捕捉因非法的 paneType 造成的动静组件渲染失败和动静组件外部的谬误,防止导致整个页面的解体。

3.0 —— 组件注册治理

在上个计划中咱们曾经提供了一个专用的配置对象,以解决动静组件的拓展性问题。然而局限性依然存在,咱们心愿可能提供一个更加通用、灵便的组件注册治理计划,以解脱只能在 Panes.ts 文件的 ExtraPanes 中进行配置性能组件的限度。

这个问题在 AREX monorepo 重构过程中显得尤为重要,起因是在 monorepo 版本中,AREX 被拆分成 arex-core 专用纯函数组件包和 arex 业务逻辑包,负责渲染主工作区的 Tabs 组件被封装到 arex-core 包中,而 tabsItems 在遍历时须要用到的映射配置 Panes 在两个包中均有定义,集中化的配置形式曾经不能满足需要,咱们须要一种能够分布式、屡次进行的组件注册治理计划。

为了解决这个问题,咱们设计了 ArexPanesManager 容器,用于治理性能页面组件的注册和获取,其简化代码如下:

export class ArexPaneManager {private static panesMap: Map<string, ArexPane> = (() => {const map = new Map<string, ArexPane>();
for (const pane in ArexPanes) {map.set(pane, ArexPanes[pane]);
}
return map;
})();
public static getPanesMap(): Map<string, ArexPane> {return this.panesMap;}
public static registerPanes(panesMap: {[key: string]: ArexPane }) {for (const name in panesMap) {const pane = panesMap[name];
if (this.panesMap.has(pane.type)) continue;
this.panesMap.set(pane.type, pane);
}
}
public static getPaneByType<T extends PanesData>(type?: string): ArexPane<T> | undefined {
return (this.panesMap.get(type || ArexPanesType.PANE_NOT_FOUND) ||
ArexPanes[ArexPanesType.PANE_NOT_FOUND]
);
}
}

借助该容器提供的 ArexPaneManager.registerPanes() 办法,能够实现在不同包中别离注册性能页面组件,最终在 arex-core 包中的 Tabs 组件借助 ArexPaneManager.getPaneByType() 办法对立获取残缺的性能页面组件的映射配置。

值得一提的是,为了对立所有性能页面组件 Pane 的标准,咱们设计了规范的 ArexPane 类型,所有呈现在主工作区 Tabs 下的性能页面组件都该当继承该类型。为此咱们提供了 ArexPaneFC 类型和 createArexPane() 办法,所有的页面性能组件先由 ArexPaneFC 定义,再经 createArexPane() 办法封装后,便失去可注册至 ArexPaneManager 进行保护治理的 ArexPane 性能页面组件。相干的类型定义和办法简化代码如下:

export type Pane<D extends PanesData = PanesData> = {
id: string;
key?: string;
type: string;
data?: D;
};
export type ArexPaneOptions = {
icon?: React.ReactNode;
type: string;
};
export type PanesData = any;
export type ArexPane<D extends PanesData = PanesData> = ArexPaneFC<D> & ArexPaneOptions;
export type ArexPaneFC<D extends PanesData = PanesData> = React.FC<{data: D}>;
export function createArexPane<D extends PanesData>(
Pane: ArexPaneFC<D>,
options: ArexPaneOptions,
): ArexPane<D> {const { noPadding = false} = options;
return Object.assign(Pane, { ...options, noPadding});
}

通过三个版本的演变,咱们最终实现了一个通用的、分布式的性能页面组件注册治理计划,该计划在 AREX monorepo 重构中失去了利用,也为 AREX 的二次开发提供了更多的可能性和便利性。代码的封装性和扩展性始终是开发过程中须要思考的重要因素,咱们在 AREX 的开发过程中也始终在思考如何进步代码的封装性和扩展性,心愿可能为二次开发者提供更好的开发体验。

  • AREX 文档:arextest.com/zh-Hans/doc…
  • AREX 官网:arextest.com/
  • AREX GitHub:github.com/arextest
  • AREX 官网 QQ 交换群:656108079

正文完
 0