我们编写前端集成测试并加快发布速度

你好!我叫Vova,我是Tinkoff的前端。我们的团队负责法人实体的两种产品。我可以在有关产品尺寸的数字中说:两名测试人员对每种产品进行完全回归需要三天的时间(不受外部因素的影响)。



这些条款意义重大,并希望与之抗衡。有几种战斗方法,主要是:



  • 将应用程序切成具有自己发布周期的较小产品。

  • 根据测试金字塔进行的产品覆盖率测试。



最后一段是我文章的主题。



图片



测试金字塔



众所周知,测试金字塔包含三个级别:单元测试,集成测试和e2e测试。我认为许多人都熟悉单元以及e2e,因此我将更详细地介绍集成测试。



作为集成测试的一部分,我们通过与UI的交互来测试整个应用程序的运行,但是,与e2e测试的主要区别在于,我们并未真正提出支持请求。这样做是为了仅检查前端所有系统的交互作用,以减少将来的e2e测试次数。



要编写集成测试,我们使用赛普拉斯。在本文中,我不会将其与其他框架进行比较,而只会说为什么会与我们在一起:



  1. 非常详细的文档。

  2. 轻松调试测试(Cypress为此创建了特殊的GUI,其中包含测试中的时间旅行步骤)。



这些要点对我们的团队很重要,因为我们没有编写集成测试的经验,并且需要一个非常简单的开始。在本文中,我想向您介绍我们走过的路,了解哪些障碍已解决,并分享实现的秘诀。



方式的开始



开始时,我将Angular Workspace与一个应用程序一起使用来组织代码。安装Cypress软件包后,带有配置和测试的cypress文件夹出现在应用程序的根目录中,我们在此选项处停止。当尝试在package.json中准备脚本以运行应用程序并在其之上运行测试时,我们遇到了以下问题:



  1. Index.html包含一些集成测试中不需要的脚本。

  2. 要运行集成测试,必须确保带有应用程序的服务器正在运行。



index.html的问题是通过一个单独的构建配置解决的-我们称之为sypress-在其中我们指定了一个自定义index.html。如何实现呢?我们在angular.json中找到您的应用程序的配置,打开构建部分,在此处为赛普拉斯添加一个单独的配置,并且不要忘记为serve-mode指定此配置。



构建示例配置:



"build": {
 ...
 "configurations": {
   … //  
   "cypress": {
     "aot": true,
     "index": "projects/main-app-integrations/src/fixtures/index.html",
     "fileReplacements": [
       {
         "replace": "projects/main-app/src/environments/environment.ts",
         "with": "projects/main-app/src/environments/environment.prod.ts"
       }
     ]
   }
 }
}


服务整合:



"serve": {
 ...
 "configurations": {
   … //  
   "cypress": {
     "browserTarget": "main-app:build:cypress"
   }
 }
}


从主要方面:对于cypress配置,我们指定了aot程序集并将文件替换为环境-这对于在测试期间创建类似于prod的程序集是必需的。



因此,我们找到了index.html,它仍然是引发应用程序,等待构建完成并在其之上运行测试的地方。为此,请使用启动服务器和测试并基于该编写脚本:



 "main-app:cy:run": "cypress run",
 "main-app:cy:open": "cypress open",
 "main-app:integrations": "start-server-and-test main-app:serve:cypress http://localhost:8808/app/user/ main-app:cy:run",
 "main-app:integrations:open": "start-server-and-test main-app:serve:cypress http://localhost:8808/app/user/ main-app:cy:open"


如您所见,有两种类型的脚本:打开和运行。开放模式将打开赛普拉斯本身的GUI,您可以在其中切换测试并使用时间旅行。运行模式仅是测试运行,并且是该运行的最终结果,非常适合在CI中运行。



根据所做工作的结果,我们能够获得一个编写第一个测试并在CI中运行它的开始框架。



单一储存库



所描述的方法有一个非常明显的问题:如果存储库中有两个或多个应用程序,则单文件夹方法是不可行的。事情就这样发生在我们身上。但这发生的方式很有趣。在推出赛普拉斯时,我们已经转向了NX,而开箱即用的美观功能使其可以与赛普拉斯一起使用。工作原理是什么?



  1. 您有一个应用程序,例如main-app,在它旁边创建了main-app-e2e应用程序。

  2. 将main-app-e2e重命名为main-app-integrations-您真了不起。



现在,您可以使用一个命令-ng e2e main-app-integrations运行集成测试NX将自动启动主应用程序,等待响应并运行测试。



不幸的是,那些目前正在使用Angular Workspace的人仍然处于观望状态,但这没关系,我也有一个食谱给您。我们将使用NX中的文件结构:



  1. 在您的应用程序旁边创建main-app-integrations文件夹。

  2. 在其中创建一个src文件夹,并将cypress文件夹的内容添加到其中。

  3. 不要忘记将cypress.json(最初会出现在根目录中)移到main-app-integrations文件夹中。

  4. 我们更正了cypress.json,并使用测试,插件和辅助命令(integrationFolder,pluginsFile和supportFile参数)指示了新文件夹的路径。

  5. 赛普拉斯可以在任何文件夹中使用测试,

    项目参数用于指定文件夹,因此我们将命令从赛普拉斯运行/打开更改为赛普拉斯运行/打开-.project./projects/main-app-integrations/src



Angular Workspace的解决方案与NX的解决方案尽可能相似,不同之处在于该文件夹是手动创建的,并且不是您的单一存储库中的项目之一。或者,您可以直接将NX构建器用于Cypress带有Cypress的NX 上的存储库示例,在那里您可以看到nx-cypress构建器的最终用途-注意angular.json以及

cart-e2e和products-e2e项目)。



视觉回归



在前五个测试之后,我们考虑了屏幕快照测试,因为事实上,有所有可能。我会先说一下,“屏幕截图测试”一词会给团队带来极大的痛苦,因为获得稳定测试的途径并非最简单。接下来,我将描述我们遇到的主要问题及其解决方案。赛普拉斯图像快照



库作为解决方案。实施过程并不需要很多时间,现在20分钟后,我们收到了应用程序的第一个屏幕截图,大小为1000×600 px。因为集成和使用太简单了,并且获得的好处可能是巨大的,所以带来了很多快乐。



在生成了五个参考屏幕截图之后,我们在CI中启动了一个测试,结果构建崩溃了。事实证明,使用open和run命令截取的屏幕截图是不同的。解决方案非常简单:仅在CI模式下获取屏幕截图,为此,他们在本地模式下删除了屏幕截图,例如:



Cypress.Commands.overwrite(
   'matchImageSnapshot',
   (originalFn, subject, fileName, options) => {
       if (Cypress.env('ci')) {
           return originalFn(subject, fileName, options);
       }

       return subject;
   },
);


在此解决方案中,我们查看了赛普拉斯中的env参数,您可以通过不同的方式对其进行设置



字型



在本地,测试开始通过重新启动,我们尝试在CI中再次运行它们。结果如下所示:







在diff屏幕截图中注意到字体的差异非常简单。在macOS上生成了参考屏幕截图,并且在CI中的代理上安装了Linux。



错误的决定



我们选择了一种标准字体(例如Ubuntu字体),它提供了最小的每像素差异,并将此字体应用于文本块(在

index.html中制作,仅用于赛普拉斯测试)。然后,我们将整体差异增加到0.05%,将每个像素差异增加到20%。使用这些参数,我们花了一个星期的时间-直到第一次需要更改组件中的文本。结果,尽管我们没有更新屏幕截图,但构建仍保持绿色。当前的解决方案已被证明是徒劳的。



正确的解决方案



最初的问题是在不同的环境中,从原理上讲,该解决方案提出了自己-Docker。赛普拉斯已经准备好了docker映像。映像有不同的变化,我们感兴趣,因为映像中已经包含赛普拉斯,并且每次都不会下载和解压缩赛普拉斯二进制文件(赛普拉斯GUI运行二进制文件,并且下载和解压缩比下载要花更长的时间。泊坞窗图片)。

基于包含的docker镜像,我们创建了自己的docker容器,为此我们制作了一个Integration-tests.Dockerfile文件,其内容类似:



FROM cypress:included:4.3.0
COPY package.json /app/
COPY package-lock.json app/
WORKDIR /app
RUN npm ci
COPY / /app/
ENTRYPOINT []


我想指出ENTRYPOINT的清零,这是由于以下事实:默认情况下,它是在cypress / included映像中设置的,并指向cypress run命令,这使我们无法使用其他命令。我们还将dockerfile分成几层,以便每次重启测试时都不必再次运行npm ci。



我们将.dockerignore文件(如果不是)添加到存储库的根目录,并且必须在其中指定node-modules /和* / node-modules /。



为了在Docker中运行测试,让我们编写一个bash脚本Integration-tests.sh,内容如下:



docker build -t integrations -f integration-tests.Dockerfile .
docker run --rm -v $PWD/projects/main-app-integrations/src:/app/projects/main-app-integrations/src integrations:latest npm run main-app:integrations


简短说明:我们构建了docker-container integration-tests.Dockerfile,并使用测试将卷指向该文件夹,以便可以从Docker获取创建的屏幕截图。



再次字体



解决了上一章中描述的问题之后,构建中出现了停顿,但是大约一天后,我们遇到了以下问题(左右分别是同一组件在不同时间拍摄的屏幕截图):







我认为最注意的是弹出窗口中的标题不足。原因很简单-字体无法加载,因为它不是通过资产连接的,而是在CDN上的。



错误的决定



从CDN下载字体,将它们放到资产中以进行赛普拉斯配置,并在我们的自定义

index.html中进行集成测试,以连接它们。有了这个决定,我们度过了一段不错的时光,直到我们更改了公司字体。没有第二次播放相同故事的愿望。



正确的解决方案



决定开始将所有必要的字体预加载

到cypress配置的index.html中,看起来像这样:



<link	
      rel="preload"
      href="...."	
      as="font"	
      type="font/woff2"	
      crossorigin="anonymous"
/>


由于没有时间加载的字体而导致的测试崩溃次数已降至最少,但未降至零:都一样,有时字体没有时间加载。赛普拉斯的KitchenSink本身提供了一个解决方案-waitForResource。

在我们的案例中,由于已经启用了字体的预加载,因此我们只需在赛普拉斯中重新定义访问命令,结果,它不仅导航到页面,而且还等待指定的字体加载。我还想补充一点,waitForResource不仅解决了字体问题,而且还解决了所有加载的静态问题,例如图片(由于这些问题,屏幕截图也被破坏了,waitForResource起到了很大作用)。应用此解决方案后,字体和任何可下载的静力学都没有问题。



动画制作



直到今天,与动画的联系才使我们头痛。在某个时候,该元素的屏幕截图将开始出现,或者在动画开始之前已拍摄了屏幕截图。这样的屏幕截图是不稳定的,并且每次将它们与参考进行比较时,都会有所不同。那么在解决动画问题时我们走了什么道路?



首要决定



最初,我们想到的最简单的事情是:在创建屏幕截图之前,请先停止浏览器一定时间,以便动画有时间完成。我们沿着100ms,200ms,500ms以及最终1000ms的链条行走。回顾过去,我知道这个决定最初很糟糕,但是我只是想警告您不要做出同样的决定。为什么糟糕 动画时间不同,CI中的代理有时也会变暗,这就是为什么页面稳定的等待时间有时会不同的原因。



第二解决方案



即使等待1秒,页面也始终无法保持稳定。经过一些研究,我们从Angular找到了一个工具- 可测试性。该原理基于跟踪ZoneJS的稳定性:



Cypress.Commands.add('waitStableState', () => {
   return cy.window().then(window => {
       const [testability]: [Testability] = window.getAllAngularTestabilities();

       return new Cypress.Promise(resolve => {
           testability.whenStable(() => {
               resolve();
           }, 3000);
       });
   });
});


因此,在创建屏幕截图时,我们调用了两个命令:cy.wait(1000)和cy.waitStableState()。



从那以后,没有一个随机删除的屏幕截图,但是让我们一起计算一下闲置浏览器所花费的时间。假设您在测试中有5个屏幕截图,每个屏幕截图都有一个稳定的等待时间,即1秒和一些随机时间,例如平均1.5秒(我没有测量现实中的平均值,所以我根据自己的感觉从头上拿走了) 。结果,我们在测试中花费了额外的12.5秒来创建屏幕截图。假设您已经编写了20个测试脚本,其中每个测试中至少有5个屏幕截图。我们可以通过20个测试来稳定多付大约4分钟的时间。 



但这不是最大的问题。如上所述,在本地运行测试时,不会追逐屏幕快照,而是在CI中追逐屏幕快照,并且由于期望,代码中的回调适用于每个屏幕快照,例如,在debounce Time上,它已经在测试中创建了随机化,因为在CI和本地它们通过不同的方式。



当前解决方案



让我们从Angular动画开始。在DOM元素上进行动画制作时,我们最喜欢的框架将ng-animating类挂起。这是我们做出决定的关键,因为现在我们需要确保该元素现在没有动画类。结果,它产生了这样一个功能:



export function waitAnimation(element: Chainable<JQuery>): Chainable<JQuery> {
   return element.should('be.visible').should('not.have.class', 'ng-animating');
}


似乎没有什么复杂的,但这就是我们决定的基础。这种方法要注意的是:截屏时,需要了解哪个元素的动画会使截屏不稳定,并在创建截屏之前添加一个断言,以验证该元素没有动画。但是动画也可以使用CSS。就像Cypress自己所说的那样,对元素的任何声明都在等待动画在其上结束- 这里这里的更多细节。也就是说,该方法的本质如下:我们有一个动画元素,并向其中添加一个断言-should('be.visible')/ should('not.be.visible')-并且Cypress本身将等待动画在元素上完成(顺便说一句,也许不需要使用ng-animating的解决方案,并且仅Cypress检查就足够了,但是现在我们使用实用程序-waitAnimation)。



如文档本身所述,赛普拉斯会检查页面上某个元素的位置,但并非所有动画都是关于位置变化的,还包括fadeIn / fadeOut动画。在这些情况下,解决方案原理是相同的:我们验证元素在页面上可见/不可见。 



从cy.wait(1000)+ cy.waitStableState()移到waitAnimation和Cypress Assertion时,我们不得不花费大约2个小时来稳定旧的屏幕截图,但结果是测试执行时间为+ 20-30秒而不是+4分钟...目前,我们正在仔细地进行屏幕截图审查:我们检查它们是否在DOM元素的动画过程中未执行,并在测试中添加了检查以等待动画。例如,我们经常在加载数据之前在页面上添加“骨骼”的显示。相应地,要求立即达到了以下要求:在DOM中创建屏幕截图时,不应显示骨骼,因为上面有平滑消失的动画。 



这种方法的问题是一个:创建屏幕截图时并不总是能够预见所有内容,并且仍然可以落入CI。处理此问题的方法只有一种-去立即编辑此类屏幕快照的创建,您不能推迟它,否则它会像滚雪球一样堆积,最终您只需要关闭集成测试即可。



屏幕截图大小



您可能已经注意到一个有趣的功能:默认的屏幕截图分辨率为1000×600 px。不幸的是,在Docker中启动时,浏览器窗口的大小存在问题:即使您通过Cypress更改了视口的大小,也无济于事。我们找到了适用于Chrome浏览器的解决方案(对于Electron,我们无法快速找到有效的解决方案,也没有获得本期中提出的解决方案)。首先,您需要更改浏览器才能在Chrome上运行测试:



  1. 对于NX,在运行cypress open / run命令时,我们不使用--browser chrome参数,对于run命令,请指定--headless参数。

  2. 对于NX,在带有测试的angular.json中的项目配置中,我们指定浏览器:chrome参数,对于将在CI中运行的配置,我们指定headless:true。



现在,我们在插件中进行编辑,并获得1440×900 px的屏幕截图:



module.exports = (on, config) => {
   on('before:browser:launch', (browser, launchOptions) => {
       if (browser.name === 'chrome' && browser.isHeadless) {
           launchOptions.args.push('--disable-dev-shm-usage');
           launchOptions.args.push('--window-size=1440,1200');

           return launchOptions;
       }

       return launchOptions;
   });
};


日期



这里的一切都很简单:如果在某个地方显示了与当前日期相关的日期,那么今天拍摄的屏幕截图将在明天出现。Fixim很简单:



cy.clock(new Date(2025, 11, 22, 0).getTime(), ['Date']);


现在是计时器。创建屏幕截图时,我们没有打扰,也没有使用中断选项,例如:



cy.matchImageSnapshot('salary_signing-several-payments', {
   blackout: ['.timer'],
});


片状测试



使用上面的建议,您可以实现最大的测试稳定性,但不能达到100%的最大稳定性,因为测试不仅会受到代码的影响,还会受到运行它们的环境的影响。



结果,某些百分比的测试偶尔会下降,例如,由于CI中代理性能的下降。首先,我们从侧面稳定测试:在获取屏幕截图之前,我们添加了必要的断言,但是在修复此类测试期间,您可以使用cypress-plugin-retries重试下降的测试



我们抽CI



在前面的章节中,我们学习了如何使用一个命令运行测试,并学习了如何使用屏幕截图测试。现在我们可以着眼于CI优化。我们的构建肯定会运行:



  1. NPM CI团队
  2. 在aot模式下提升应用程序。
  3. 运行集成测试。


让我们看一下第一点和第二点,并了解在其他CI构建中(与应用程序组装一起进行的构建)执行类似的步骤。

主要区别不是运行服务,而是构建。因此,如果我们可以使用集成测试在构建中获得一个已经组装好的应用程序,并使用它来提升服务器,那么我们可以通过测试来减少构建的执行时间。



我们为什么需要它?只是我们的应用程序很大而充实

npm ci + npm在CI中的代理上以aot模式启动大约需要15分钟,这在原则上需要代理付出很多努力,并且集成测试也在此之上运行。假设您已经编写了20多个测试,而在第19个测试上,由于代理的负担很重,您的浏览器崩溃并运行了测试。如您所知,重新开始构建将再次等待依赖项的安装和应用程序的启动。



此外,我将只讨论应用程序端的脚本。您将需要解决自己在任务之间将工件转移到CI的问题,因此我们要记住,具有集成测试的新版本将可以从任务中访问已组装的应用程序,以进行应用程序构建。



静态服务器



我们需要ng服务替换,以通过我们的应用程序提升服务器。有很多选择,我将从我们的first- angle-http-server开始。它的配置没有什么复杂的:我们安装依赖项,指示我们的静态变量位于哪个文件夹中,指示要在哪个端口上引发应用程序,并且很高兴。



这个解决方案对于我们整个20分钟就足够了,然后我们意识到我们想将一些请求代理到测试电路。用于angular-http-server的连接代理失败。最终的解决方案是将服务器升级到Express。为了解决该问题,我们使用了express和express-http-proxy本身。我们将使用

express.static 分发静态变量,结果得到了与此脚本类似的脚本:



const express = require('express');
const appStaticPathFolder = './dist';
const appBaseHref = './my/app';
const port = 4200;
const app = express();

app.use((req, res, next) => {
   const accept = req
       .accepts()
       .join()
       .replace('*/*', '');

   if (accept.includes('text/html')) {
       req.url = baseHref;
   }

   next();
});
app.use(appBaseHref, express.static(appStaticPathFolder));
app.listen(port);


这里有趣的一点是,在侦听应用程序的baseHref路由之前,我们还处理所有请求并查找对index.html的请求。当测试转到路径不同于baseHref的应用程序页面时,可以执行此操作。如果您不执行此技巧,那么当您转到应用程序的除主页以外的任何页面时,都会收到404错误。现在让我们添加一些代理:



const proxy = require('express-http-proxy');

app.use(
   '/common',
   proxy('https://qa-stand.ru', {
       proxyReqPathResolver: req => '/common' + req.url,
   }),
);


让我们仔细看看发生了什么。有常量:



  1. appStaticForlderPath-应用程序静态变量所在的文件夹。 
  2. appBaseHref-您的应用程序可能具有baseHref,如果没有,则可以指定'/'。


我们代理所有以/ common开头的请求,代理时,我们使用proxyReqPathResolver设置保存请求具有的相同路径。如果您不使用它,那么所有请求都将直接发送到https://qa-stand.ru。



自定义index.html



我们需要使用自定义index.html解决该问题,该自定义index.html在ng以Cypress模式提供服务时使用。让我们在node.js中编写一个简单的脚本。我们以index.modern.html作为初始参数,我们需要将其转换为index.html并从此处删除不必要的脚本:



const fs = require('fs');
const appStaticPathFolder = './dist';

fs.copyFileSync(appStaticPathFolder + '/index.modern.html', appStaticPathFolder + '/index.html');

fs.readFile(appStaticPathFolder + '/index.html', 'utf-8', (err, data) => {
   const newValue = data
       .replace(
           '<script type="text/javascript" src="/auth.js"></script>',
           '',
       )
       .replace(
           '<script type="text/javascript" src="/analytics.js"></script>',
           '',
       );

   fs.writeFileSync(appStaticPathFolder + '/index.html', newValue, 'utf-8');
});


剧本



我真的不想再次使用所有依赖项的npm ci来在CI中运行测试(毕竟,这已经在应用程序构建的任务中完成了),因此想到了用我们自己的package.json为所有这些脚本创建一个单独的文件夹。让我们将文件夹命名为例如Integration-tests-scripts,然后在其中放置三个文件:server.js,create-index.js,package.json。上面介绍了前两个文件,现在我们将分析package.json的内容:



{
 "name": "cypress-tests",
 "version": "0.0.0",
 "private": true,
 "scripts": {
   "create-index": "node ./create-index.js",
   "main-app:serve": "node ./server.js",
   "main-app:cy:run": "cypress run --project ./projects/main-app-integrations ",
   "main-app:integrations": "npm run create-index && start-server-and-test main-app:serve http://localhost:4200/my/app/ main-app:cy:run"
 },
 "devDependencies": {
   "@cypress/webpack-preprocessor": "4.1.0",
   "@types/express": "4.17.2",
   "@types/mocha": "5.2.7",
   "@types/node": "8.9.5",
   "cypress": "4.1.0",
   "cypress-image-snapshot": "3.1.1",
   "express": "4.17.1",
   "express-http-proxy": "^1.6.0",
   "start-server-and-test": "1.10.8",
   "ts-loader": "6.2.1",
   "typescript": "3.8.3",
   "webpack": "4.41.6"
 }
}


package.json仅包含运行集成测试所需的依赖项(支持打字稿和屏幕截图测试)以及用于启动服务器,创建index.html的脚本以及从在Angular Workspace中运行集成测试的章节中已知的启动服务器和测试...



跑步



我们将集成测试的执行包装在新的Dockerfile中-Integration -tests-ci.Dockerfile



FROM cypress/included:4.3.0
COPY integration-tests-scripts /app/
WORKDIR /app
RUN npm ci
COPY projects/main-app-integrations /app/projects/main-app-integrations
COPY dist /app/dist
COPY tsconfig.json /app/
ENTRYPOINT []


底线很简单:将integration-tests-scripts文件夹复制并展开到应用程序的根目录,然后复制运行测试所需的所有内容(此套件可能与您有所不同)。与前一个文件的主要区别在于我们不将整个应用程序复制到docker容器中,而只是对CI中的测试执行时间进行了最小的优化。



创建具有以下内容integration-tests-ci.sh文件



docker build -t integrations -f integration-tests-ci.Dockerfile .
docker run --rm -v $PWD/projects/main-app-integrations/src:/app/projects/main-app-integrations/src integrations:latest npm run main-app:integrations


运行带有测试的命令时,位于Integration-tests-scripts文件夹中的package.json将成为根目录,并在其中启动main-app:Integrations命令。相应地,由于此文件夹将扩展到根目录,因此应使用所有应用程序都将从根目录而不是Integration-tests-scripts文件夹启动的想法来指示具有应用程序静态信息的文件夹的路径。



我还想说一点:我称最终的bash脚本用于运行集成测试,因为它的发展方式有所不同。您不需要这样做,这样做只是为了阅读本文的方便。您应该始终只剩下一个正在开发的文件,例如Integration-tests.sh。如果存储库中有多个应用程序,并且它们的准备方法不同,则可以使用bash中变量,或每个应用程序使用不同的文件-取决于您的需求。



结果



有很多信息-我认为现在值得根据上面写的内容进行总结。

使用一些屏幕截图测试准备用于本地编写和运行测试的工具:



  1. 放置赛普拉斯的依赖项。
  2. 准备一个带有测试的文件夹:

    1. Angular Single Application-将所有内容保留在cypress文件夹中。
    2. Angular Workspace-在将要测试的应用程序旁边创建集成应用程序的文件夹名称,并将所有内容从cypress文件夹传输到该文件夹​​。
    3. NX-将项目从appname-e2e重命名为appname-integrations。


  3. cypress- — build- Cypress, aot, index.html, environment prod- serve- Cypress ( , - prod-, ).
  4. :

    1. Angular Single Application — serve- cypress- , start-server-and-test.
    2. Angular Workspace — Angular Single Application, cypress run/open.
    3. NX — ng e2e.


  5. -:

    1. cypress-image-snapshot.
    2. CI.
    3. 在测试中,我们不会随机截图。如果屏幕截图之前有动画,请确保等待它-例如,将Cypress Assertion添加到动画元素。
    4. 日期通过cy.clock弄湿了,或者在截屏时使用了停电选项。
    5. 我们希望通过cy.waitForResource定制命令在运行时加载任何静态信息(图像,字体等)。


  6. 我们将其全部包装在Docker中:

    1. 准备Dockerfile
    2. 我们创建一个bash文件。




 我们在组装的应用程序之上运行测试:



  1. 在CI中,我们学习在两次构建之间抛出组装好的应用程序的工件(它留在您身上)。
  2. 准备Integration-tests-scripts文件夹:

    1. 用于提高应用程序服务器的脚本。
    2. 用于更改index.html的脚本(如果您对初始index.html感到满意,可以跳过它)。
    3. 使用必要的脚本和依赖项将其添加到package.json文件夹中。
    4. 我们正在准备一个新的Dockerfile。
    5. 我们创建一个bash文件。


有用的链接



  1. Angular Workspace + Cypress + CI — Angular Workspace CI , ( typescript).

  2. Cypresstrade-offs.

  3. Start-server-and-test — , .

  4. Cypress-image-snapshot — -.

  5. Cypress recipes — Cypress, .

  6. Flaky Tests — , Google.

  7. Github Action — Cypress GitHub Action, README , — wait-on. docker.




All Articles