Jest是否以异步方式运行用describe()定义的测试套件?

时间:2019-08-06 02:10:40

标签: javascript angularjs jestjs puppeteer

问题摘要::我正在编写几个测试套件(使用Jest和Puppeteer)以自动化AngularJS应用的index.html页面的测试。不幸的是,我在运行测试时看到一些奇怪的行为,我认为这与Jest运行各种测试套件的顺序有关。

背景:我正在使用Jest(v24.8.0)作为测试框架。我正在使用Puppeteer(v1.19.0)启动并控制可在其上执行测试的Chromium浏览器。

我的代码:

<!-- index.html -->
<div ng-app="myApp" ng-controller="myCtrl as ctrl">
    <form name="form1">
        <md-input-container>
            <label class="md-required">Name</label>
            <input ng-model="ctrl.name1"></input>
        </md-input-container>
        <md-dialog-actions>
            <button class="md-primary md-button" ng-transclude type="submit">Submit</button>
        </md-dialog-actions>
    </form>
    <form name="form2">
        <md-input-container>
            <label class="md-required">Name</label>
            <input ng-model="ctrl.name2"></input>
        </md-input-container>
        <md-dialog-actions>
            <button class="md-primary md-button" ng-transclude type="submit">Submit</button>
        </md-dialog-actions>
    </form>
</div> 
// index.spec.js
const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.goto('https://my-site.com');

    describe('form 1', async () => {
        test('populate form 1', async () => {
            let formSelector = 'form[name="form1"]';
            await page.waitForSelector(formSelector+' input', {timeout: 3000});
            await page.click(formSelector+' input');
            await page.keyboard.type('casey');
            let submitButtonSelector = 'form[name="form1"] button[type="submit"]';
            await page.click(submitButtonSelector);
        });
    });
    describe('form 2', async () => {
        test('populate form 2', async () => {
            let formSelector = 'form[name="form2"]';
            await page.waitForSelector(formSelector+' input', {timeout: 3000});
            await page.click(formSelector+' input');
            await page.keyboard.type('jackie');
            let submitButtonSelector = 'form[name="form2"] button[type="submit"]';
            await page.click(submitButtonSelector);
        });
    });
    await browser.close();
})();

测试行为: 有时,当我运行npm test时,似乎正在运行我的两个测试套件'form1''form2'(我用describe定义) (尽管我知道这在Javascript中是不可能的,所以我假设Jest异步运行不同的测试套件)。无论哪种方式,当我在非无头模式下运行测试时,都可以看到form1的名称输入中填充了'jackie',即使它应该是'casey'。在那之后,form2永远不会被填写(即使我的第二个测试套件应该这样做)并且测试完成,然后Jest通知我'populate form 2'已经失败。再一次,这不是每次我运行测试时都会发生,因此您可能无法复制我的问题。

我的问题:

  1. Jest是否并行/异步运行测试套件? 注意:我不是在谈论测试套件中用test定义的单个测试,我知道如果我将它们传递给async函数,它们将异步运行。

  2. 如果Jest确实异步运行测试套件,如何禁用它?还是更好,是为智能/常规/最优提供不同的测试套件不同的browser实例,以便它们在完全独立的窗口中运行?还有其他方法可以确保测试套件分别和/或同步运行吗?

  3. 如果Jest不异步运行测试套件,那么您为什么认为我看到这种现象?

我之所以问是因为我想找到一种方法来确保我所有的测试都可以一直通过,而不是仅仅一次通过。从长远来看,这将使确定我在开发过程中所做的更改是否破坏任何东西变得容易。

在此先感谢所有Jest / Puppeteer黑客!

1 个答案:

答案 0 :(得分:1)

默认情况下,Jest会根据max workers但不是runs all describe and tests blocks serially within a file在每个文件中同时运行测试。

如果您要使用run in band顺序运行所有文件,则将删除工作池。

但是,我建议重构,您可以嵌套describe

// instead of IIFE, nest describes for better parsing for jest and readability
describe('forms', async () => {
    const browser = await puppeteer.launch({headless: false});

    describe('form 1', () => {
        test('populate form 1', async () => {
            // make every test independent of the other to avoid leaky scenarios
            const page = await browser.newPage();
            await page.goto('https://my-site.com');
            let formSelector = 'form[name="form1"]';
            await page.waitForSelector(formSelector+' input', {timeout: 3000});
            await page.click(formSelector+' input');
            await page.keyboard.type('casey');
            let submitButtonSelector = 'form[name="form1"] button[type="submit"]';
            await page.click(submitButtonSelector);
        });
    });
    describe('form 2', () => {
        test('populate form 2', async () => {
            const page = await browser.newPage();
            await page.goto('https://my-site.com');
            let formSelector = 'form[name="form2"]';
            await page.waitForSelector(formSelector+' input', {timeout: 3000});
            await page.click(formSelector+' input');
            await page.keyboard.type('jackie');
            let submitButtonSelector = 'form[name="form2"] button[type="submit"]';
            await page.click(submitButtonSelector);
        });
    });

    await browser.close();
})

更新

在NodeJS中,您可以spawn processes,就开玩笑而言,每个进程都是一个节点实例,它们通过标准IO进行通信。您可以告诉jest使用CLI选项生成多少个,但是,当使用少量jest的worker时,我会遇到性能下降的情况,因为NodeJS实例很重,而且生成/同步可能比实际运行更昂贵或很少有工人。

此外,它们的运行方式也没有任何保证,如果您希望产生10个进程,则您的OS可能会将所有进程调度到同一CPU线程,并且它们将按顺序运行。