代码之家  ›  专栏  ›  技术社区  ›  Majesty

量角器:随机测试失败

  •  1
  • Majesty  · 技术社区  · 7 年前

    我在Ubuntu 14.04上运行,同样的问题与 Chrome Version 71.0.3578.80 Firefox Version 60.0.2 . AngularJS Version 1.7.2 Protractor Version 5.4.0 . 我相信问题在我的代码中的某个地方,所以下面我提供了一个现有代码库的示例。

    这是我的量角器配置

    exports.config = {
      rootElement: '[ng-app="myapp"]',
      framework: 'jasmine',
      seleniumAddress: 'http://localhost:4444/wd/hub',
      specs: ['./e2e/**/*protractor.js'],
      SELENIUM_PROMISE_MANAGER: false,
      baseUrl: 'https://localhost/',
      allScriptsTimeout: 20000,
      jasmineNodeOpts: {
        defaultTimeoutInterval: 100000,
      },
       capabilities: {
         browserName: 'firefox',
         marionette: true,
         acceptInsecureCerts: true,
         'moz:firefoxOptions': {
           args: ['--headless'],
         },
       },
    }
    

      capabilities: {
        browserName: 'chrome',
         chromeOptions: {
           args: [ "--headless", "--disable-gpu", "--window-size=1920,1080" ]
         }
      },
    

    最后,我的测试工具失败了几次

    const InsurerViewDriver = require('./insurer-view.driver');
    const InsurerRefundDriver = require('./insurer-refund.driver');
    const { PageDriver } = require('@utils/page');
    const { NotificationsDriver } = require('@utils/service');
    const moment = require('moment');
    
    describe(InsurerViewDriver.pageUrl, () => {
      beforeAll(async () => {
        await InsurerViewDriver.goToPage();
      });
    
      it('- should test "Delete" button', async () => {
        await InsurerViewDriver.clickDelete();
    
        await NotificationsDriver.toBeShown('success');
        await PageDriver.userToBeNavigated('#/setup/insurers');
    
        await InsurerViewDriver.goToPage();
      });
    
      describe('Should test Refunds section', () => {
        it('- should test refund list content', async () => {
          expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');
    
          const refunds = InsurerRefundDriver.getRefunds();
          expect(await refunds.count()).toBe(1);
    
          const firstRow = refunds.get(0);
          expect(await firstRow.element(by.binding('item.name')).getText()).toEqual('Direct');
          expect(await firstRow.element(by.binding('item.amount')).getText()).toEqual('$ 50.00');
          expect(await firstRow.element(by.binding('item.number')).getText()).toEqual('');
          expect(await firstRow.element(by.binding('item.date')).getText()).toEqual(moment().format('MMMM DD YYYY'));
        });
    
        it('- should test add refund action', async () => {
          await InsurerRefundDriver.openNewRefundForm();
    
          const NewRefundFormDriver = InsurerRefundDriver.getNewRefundForm();
    
          await NewRefundFormDriver.setPayment(`#555555, ${moment().format('MMMM DD YYYY')} (amount: $2,000, rest: $1,500)`);
          await NewRefundFormDriver.setPaymentMethod('Credit Card');
    
          expect(await NewRefundFormDriver.getAmount()).toEqual('0');
          await NewRefundFormDriver.setAmount(200.05);
          await NewRefundFormDriver.setAuthorization('qwerty');
    
          await NewRefundFormDriver.submit();
          await NotificationsDriver.toBeShown('success');
    
          const interactions = InsurerRefundDriver.getRefunds();
          expect(await interactions.count()).toBe(2);
    
          expect(await InsurerViewDriver.getInsurerTitleValue('Balance:')).toEqual('Balance: $ 2,200.05');
          expect(await InsurerViewDriver.getInsurerTitleValue('Wallet:')).toEqual('Wallet: $ 4,799.95');
        });
      });
    });
    

      // PageDriver.userToBeNavigated
      this.userToBeNavigated = async function(url) {
        return await browser.wait(
          protractor.ExpectedConditions.urlContains(url),
          5000,
          `Expectation failed - user to be navigated to "${url}"`
        );
      };
    
      this.pageUrl = '#/insurer/33';
    
      // InsurerViewDriver.goToPage
      this.goToPage = async () => {
        await browser.get(this.pageUrl);
      };
    
      // InsurerViewDriver.clickDelete()
      this.clickDelete = async () => {
        await $('[ng-click="$ctrl.removeInsurer()"]').click();
        await DialogDriver.toBeShown('Are you sure you want to remove this entry?');
        await DialogDriver.confirm();
      };
    
      // NotificationsDriver.toBeShown
      this.toBeShown = async (type, text) => {
        const awaitSeconds = 6;
        return await browser.wait(
          protractor.ExpectedConditions.presenceOf(
            text ? element(by.cssContainingText('.toast-message', text)) : $(`.toast-${type}`)
          ),
          awaitSeconds * 1000,
          `${type} notification should be shown within ${awaitSeconds} sec`
        );
      }
    
      // InsurerRefundDriver.getRefunds()
      this.getRefunds = () => $('list-refunds-component').all(by.repeater('item in $data'));
    
    // InsurerViewDriver.getInsurerTitleValue
    this.getInsurerTitleValue = async (text) => {
        return await element(by.cssContainingText('header-content p', text)).getText();
      };
    

    我不能在这里上传整个代码来让您更好地理解,因为到目前为止我有很多代码,但上面提供的代码正是我在任何地方使用的方法的示例,有人看到我的代码中有问题吗?谢谢

    4 回复  |  直到 7 年前
        1
  •  2
  •   Sergey Pleshakov    7 年前

    首先,在导出配置之前添加此块

    process.on("unhandledRejection", ({message}) => {
        console.log("\x1b[36m%s\x1b[0m", `Unhandled rejection: ${message}`);
    });
    

    如果您错过了async/Wait anywhere,这基本上会以彩色方式登录到控制台,这会让您确信您没有错过任何东西。

    其次,我会安装“Gragrator console”插件,以确保浏览器控制台中没有错误/拒绝(即排除应用程序端出现问题的可能性),并添加到配置中

    plugins: [{
        package: "protractor-console",
        logLevels: [ "severe" ]
    }]
    

    1) 我在WebStorm中创建了运行配置,如我在这里的评论所述(查找我的) How to debug angular protractor tests in WebStorm

    3) 然后使用创建的运行配置逐行执行测试。

    当您开始调试过程时,webstorm会打开一个包含三个部分的面板:框架、控制台和变量。当变量部分有一条消息时 connected to localhost 并且没有列出变量,这意味着您的步骤仍在执行中。加载完成后,您可以查看所有变量,并可以执行下一个命令。所以这里的主要原则是你们点击单步跳过按钮,然后观察变量部分。如果变量出现在应用程序加载完成之前(等待方法已执行,但应用程序仍在加载,这是错误的),则需要使用此方法。通过这种方式,我在自定义等待方法中发现了很多漏洞。

    最后,如果这不起作用,请附加错误的堆栈跟踪并ping我

        2
  •  1
  •   Old Pro    7 年前

    我很关心这个代码片段

    describe(InsurerViewDriver.pageUrl, () => {
      beforeAll(async () => {
        await InsurerViewDriver.goToPage();
      });
    
      it('- should test "Delete" button', async () => {
        await InsurerViewDriver.clickDelete();
    
        await NotificationsDriver.toBeShown('success');
        await PageDriver.userToBeNavigated('#/setup/insurers');
    
        await InsurerViewDriver.goToPage(); // WHY IS THIS HERE?
      });
    
      describe('Should test Refunds section', () => {
        it('- should test refund list content', async () => {
          // DOESN'T THIS NEED SOME SETUP?
          expect(await InsurerRefundDriver.getTitle()).toEqual('REFUNDS');
    // <truncated>
    

    你不应该依赖第一个 it 子句来设置它下面的套件。你没有发布你的密码 InsurerRefundDriver.getTitle() 但是,如果该代码没有将浏览器发送到正确的URL,然后等待页面完成加载,那就是一个问题。你应该有 await InsurerViewDriver.goToPage(); 在一个 beforeEach 条款

        3
  •  1
  •   Majesty    7 年前

      this.goToPage = async () => {
        await browser.get(this.pageUrl);
      };
    

    结果是 browser.get 方法是在url更改时解析的,但现在是在angularjs完成编译时解析的。我在每个测试套件中都使用了相同的方法,这就是为什么我的测试不一致地失败,有时在测试开始之前页面没有完全加载。

    因此,这里有一个方法,做到了这一点

      this.goToPage = async () => {
        await browser.get(this.pageUrl);
        await browser.wait(EC.presenceOf(`some important element`), 5000, 'Element did not appear after route change');
      };
    

        4
  •  0
  •   Abdel    7 年前

    这似乎是由于异步javascript造成的。

    browser.ignoreSynchronization=true;对您的所有测试具有全局影响。您可能必须将其设置回false,以便量角器等待angular完成页面渲染。e、 g.在每次活动前的第二次活动中或之前