Protractor自动化测试框架基础

目录

前言

一、环境搭建

 二、自动化测试试例

1、conf.js

1)framework: 'jasmine'

2) directConnect: true

3) SELENIUM_PROMISE_MANAGER: false

4) specs: ['spec.js']

2、spec.js

3、单个用例写法

4、多个用例写法

5、执行自动化测试

三、protractor实例与browser对象

1、ProtractorBrowser对象

1.1 browser.angularAppRoot(value)

1.2 browser.waitForAngularEnabled(boolean)

1.3 browser.getProcessedConfig( )

1.4 browser.forkNewDriverInstance()

1.5 browser.restart()

1.6  browser.restartSync()

1.7 browser.useAllAngular2AppRoots(value)

1.8 browser.waitForAngular()

1.9 browser.driver.findElement(locator)

1.10  browser.driver.findElements(locator)

1.11  browser.addMockModule()

1.12  browser.clearMockModules()

1.13 browser.removeMockModule()

1.14 browser.getRegisteredMockModules()

 1.15 browser.driver.get()

1.16 browser.refresh()

1.17 browser.driver.navigate()

1.18 browser.setLocation()

1.19  browser.controlFlowIsEnabled(boolean)

2、webdriver.WebDriver

2.1 browser.actions()

2.2 browser.touchActions()

2.3 browser.executeScript()

2.4 browser.call()

2.5 browser.wait()

2.6 browser.sleep()

2,7 browser.getPageSource()

2.8 browser.close()

2.9 browser.getCurrentUrl()

2.10 browser.getTitle()

2.11   browser.takeScreenshot()

2.12 browser.switchTo()

3、常见浏览器操作

3.1 浏览器刷新

3.2 鼠标悬停操作

3.3 浏览器最大化

四、ElementFinder和ElementArrayFinder对象

1、ElementFinder对象

1.1 ElementFinder对象的方法 element(locator)

1、clone()

2、locator()

3、getWebElement()

4、all(sublocator)

5、element(sublocator)

6、$$(sublocator)

7、$(sublocator)

8、isPresent()

9、isElementPresent(sublocator)

10、evaluate(string)

11、allowAnimations(boolean)

12、equals(ElementFinder | webdriver.WebElement)

13、getWebElement().getDriver()

14、getWebElement().getId()

15、getWebElement().findElement()

16、click()

17、sendKeys(string)

18、getTagName()

​编辑19、getCssValue(cssStyleProperty: string)

20、getAttribute(attributeName: string)

21、getText()

22、getSize()

23、getLocation()

24、isEnabled()

25、isSelected()

26、submit()

27、clear()

28、isDisplayed()

29、takeScreenshot()

 2、ElementArrayFinder对象

2.1 ElementArrayFinder对象的方法 element.all(locator)

1、clone()

2、all(sublocator)

3、filter(callback)

4、get(index: number)

 5、first()

6、last()

7、count()

8、isPresent()

9、locator()

10、then(thenFunction)

11、each(eachFunction)

12、map(mapFunction)

13、reduce(reduceFn)

14、evaluate(expression: string)

15、allowAnimations(boolean)

五、 Protractor Locators

1、ProtractorBy

1.1 by.addLocator(locatorName, functionOrScript)

1.2 by.binding

1.3 by.exactBinding

1.4 by.model

1.5 by.buttonText

1.6 by.partialButtonText

1.7 by.repeater

1.8 by.exactRepeater

1.9 by.cssContainingText

1.10  by.options

1.11 by.deepCss

2、 webdiver.By

2.1 by.className

2.2 by.css

2.3 by.id

 2.4 by.linkText

2.5  by.js(expression)

2.6 by.name

2.7 by.partialLinkText

2.8 by.tagName

2.9 by.xpath

 六、ExpectedConditions(预期条件)

1、ExpectedConditions.not

2、ExpectedConditions.and

3、ExpectedConditions.or

4、ExpectedConditions.alertIsPresent

5、ExpectedConditions.elementToBeClickable

6、ExpectedConditions.textToBePresentInElement

7、ExpectedConditions.textToBePresentInElementValue

8、ExpectedConditions.titleContains

9、ExpectedConditions.titleIs

10、ExpectedConditions.presenceOf

11、ExpectedConditions.stalenessOf

12、ExpectedConditions.visibilityOf

13、ExpectedConditions.invisibilityOf

14、ExpectedConditions.elementToBeSelected

七、protractor 断言

1、toBe

2、toEqual

3、toMatch

4、toBeDefined

5、toBeUndefined

6、toBeNull

7、toBeTruthy

8、toBeFalsy

9、toContain

10、toBeLessThan

11、toBeGreaterThan

12、toBeCloseTo

13、toThrow

14、toThrowError

八、Hook函数

beforeAll

beforeEach

afterAll

afterEach

九、protractor生成报告

拓展知识

1、变量名前加下划线

2、使用browser.method()和browser.method()方法区别

3、同步、异步、阻塞、非阻塞

4、protractor核心API

5、多级路径表示

6、JS中的立即执行函数


前言

引用自   Web自动化测试-Protractor基础(一)_protractor测试_apolis的博客-CSDN博客

        Protractor是一个建立在WebDriverJS基础上的端到端(E2E)的AngularJS JavaScript Web应用程序测试框架

        Protractor通过程序模拟用户在浏览器中操作来做自动化测试。
Protractor可以为angular应用做自动化测试,它有些api是专门为angular提供的。如果不是angular应用,也可以用Protractor做自动化测试,只要避开调用angular专属api就可以了,本文的示例就是非angular应用。

protractor框架原理

angular简介:

        Angular是一种用于构建Web应用程序的开源框架,最初由Google开发。Angular采用了一种组件化的方法,其中应用程序被划分为多个可重复使用的组件,这些组件之间可以交互和通信。Angular还提供了一种声明式模板语言,可以用于定义组件的视图和行为。

        Angular包含了一些强大的功能,例如依赖注入、模块化、路由器和HTTP模块等,这些功能使得开发者可以更加轻松地构建复杂的Web应用程序。此外,Angular还提供了一些工具和库,例如Angular CLI、Angular Material和NgRx等,可以帮助开发者更高效地开发和维护Web应用程序。

        总之,Angular是一个功能强大且灵活的Web开发框架,它可以帮助开发者构建高效、可维护的Web应用程序。

jasmine简介:

        Jasmine是一种用于JavaScript应用程序的行为驱动开发(BDD)测试框架。它提供了一组用于描述应用程序行为的函数和语法,可以帮助开发者编写易于维护和易于阅读的测试用例

        使用Jasmine编写的测试用例包括一系列描述性的语句,这些语句描述了应用程序中期望发生的行为。Jasmine提供了一些基本的断言函数,用于验证测试用例中的预期结果是否与实际结果相符。开发者可以通过定义自己的自定义匹配器来扩展Jasmine的功能

        Jasmine还提供了一个独立运行的测试环境,可以在浏览器中运行测试用例,也可以在命令行界面中运行测试用例。此外,Jasmine还可以与其他测试工具和框架(如Karma)一起使用,以提供更全面的测试覆盖率。

        总之,Jasmine是一种强大的测试框架,可以帮助开发者编写高质量、易于维护的JavaScript应用程序测试用例。

protractor官网

angular应用介绍

Angular介绍 - 简书

Karma-Protractor 学习_左手121的博客-CSDN博客

一、环境搭建

1、安装NodeJS,版本要求支持async await

2、使用npm全局安装Protractor

npm install -g protractor

protractor --version

webdriver-manager version

若提示该系统禁止运行脚本时,查看此解决方案 点击这里

若提示名不识别,则点击这个 方案一  方案二

3、安装kama-jasmine

npm install --save-dev karma-jasmine

4、安装Protractor需要用到BrowserDriver等,命令行执行

webdriver-manager update

都会下载最新的chromedriver和geckodriver

 若执行报错,则查看保存原因,自行下载最新的driver或相关文件替换,下载地址

5、webdriver-manager start

6、npm初始化,用于调试

npm init -y

7、安装q模块

npm install q --save

以上命令均在vscode终端执行

设置vscode自动保存,打开设置

 设置自动保存类型

 二、自动化测试试例

下面来做一个例子,涉及两个文件

1、conf.js

配置参数详解

Protractor配置项

exports.config = {
    framework: 'jasmine',
    directConnect: true,
    SELENIUM_PROMISE_MANAGER: false,
    specs: ['spec.js']
}

解释一下这4个配置项

1)framework: 'jasmine'

指定使用测试框架jasmine,实例使用jasmine的脚本

describe("A suite is just a function", function() {
    var a;
    it("and so is a spec", function() {
        a = true;
        expect(a).toBe(true);
    });
});

jasmine提供了以下功能:

        describe 和 it 是 Jasmine 测试框架的语法格式。browser 是通过 protractor 创建的全局变量。它用于浏览器范围的命令控制,比如通过 browser.get 进行导航。jasmine的语法课参考jasmine官网Jasmine Documentation

  • 函数it定义了一个测试用例。
  • 函数itexpect(a).toBe(true) 表示对意思是期望a为true。如果a不等于true,测试用例执行失败。
  • 函数describe里面可以包含多个it,起到一个对测试用例分组的作用。
  • 测试脚本执行完毕后,会打出结果,多少测试用例执行成功,多少执行失败以及失败的原因。
    想了解更多jasmine的信息,点击这里

2) directConnect: true

这个图最左边运行的是测试脚本,最右边是浏览器。
测试脚本在Node中运行,测试脚本想要控制浏览器行为,要通过中间的Selenium ServerSelenium Server担当一个翻译转述的角色。

设置directConnect: true代表测试脚本将不经过Selenium Server,直接和浏览器通信,这样环境更简单,更快速。

3) SELENIUM_PROMISE_MANAGER: false

字面意思就是不使用selenium promise manager
看下面这段测试脚本:

it('test', function () {
    ......
    browser.driver.get('https://www.baidu.com');
    $('#kw').sendKeys('protractor');
    $('#su').click();
    ......
});

这段测试脚本在操作浏览器,底层用的是webdriverjs
打开百度页面,输入protractor,点击搜索。
这三个操作都是异步的,我们需要每个异步操作执行完毕后再执行下个操作
想达到这个效果,我们可以使用callback,但最终会导致callback hell。

为了避免callback hell,promise manager出场了,它的作用就是让你用同步的写法去写异步操作,效果是一个异步操作执行完毕后才执行下一个

我们这里将promise manager禁用了又是为什么呢?

webdriverjs很多年前就有了,promise manager是webdriverjs自己实现的,代码很多,维护也困难。ES2017中async await得到了支持,使用async await同样可以达到想要的效果。因此webdriverjs已准备放弃promise manager,推荐直接使用async await。这就是为什么在环境搭建时要求大家安装支持async await版本的NodeJS

4) specs: ['spec.js']

指定要执行的测试脚本,是个数组,代表可以放多个脚本文件

2、spec.js

写自动化测试脚本

describe('测试百度搜索', function () {
    it('测试protractor官网会不会出现在第一个搜索结果中', async function () {
        await browser.waitForAngularEnabled(false);
        await browser.driver.get('https://www.baidu.com');

        await $('#kw').sendKeys('protractor');
        await $('#su').click();

        var EC = protractor.ExpectedConditions;
        await browser.wait(EC.presenceOf($('.result.c-container h3')), 5000);

        await expect($$('.result.c-container h3 a').first().getText())
            .toBe('Protractor - end-to-end testing for AngularJS');
    });
});

代码用了async await。await后面是一个异步操作,程序会阻塞在这里,直到异步操作执行完毕后,才会继续向下执行。

开头说过,Protractor是为angular设计的。
脚本通过browser.get('url goes here')让浏览器加载一个angular应用,这句话会一直阻塞到angular应用初始化完毕。如果加载的不是一个angular应用,会抛异常出来。

如果想让Protractor测试非angular应用,下面两行代码是必须的

// 不需要等待angular应用初始化完毕,因为不是angular应用
await browser.waitForAngularEnabled(false);
// 使用browser.driver.get加载非angular应用,browser.get用于加载angular应用
await browser.driver.get('https://www.baidu.com');

选择dom元素,输入搜索字符串,点击搜索按钮

// 搜索框输入protractor
await $('#kw').sendKeys('protractor');
// 点击搜索按钮
await $('#su').click();

点击搜索后,搜索结果不是立刻出现的,要等待一阵

var EC = protractor.ExpectedConditions;
// 等待结果的dom元素出现,超时时间5000毫秒,超过超时时间认为测试用例执行失败
await browser.wait(EC.presenceOf($('.result.c-container h3')), 5000);

断言第一个搜索结果的header和Protractor官网是否一样

// $$选取所有符合css选择符的元素
await expect($$('.result.c-container h3 a').first().getText())
    .toBe('Protractor - end-to-end testing for AngularJS');

3、单个用例写法

describe('Protractor Demo App',function(){
    it('should add one and two',function(){
        browser.get('http://juliemr.github.io/protractor-demo/');
        element(by.model('first')).sendKeys('1');
        element(by.model('second')).sendKeys('2');
        element(by.id('gobutton')).click(); 
        expect(element(by.binding('latest')).getText()).toEqual('3'); }); }
        );

4、多个用例写法

describe('Protractor Demo App',function(){
    var fristNumber = element(by.model('first'));
    var secondNumber = element(by.model('second'));
    var goBtn = element(by.id('gobutton'));
    var lastestResult = element(by.binding('latest'));
    function add(a,b){
        fristNumber.sendKeys(a);
        secondNumber.sendKeys(b);
        goBtn.click();
    }
    beforeEach(function(){
        browser.get('http://juliemr.github.io/protractor-demo/');
    });
    it('should have a expect title',function(){
        expect(browser.getTitle()).toEqual('Super Calculator');
    });
    it('should add one and two',function(){
        add(1,2);
        expect(element(by.binding('latest')).getText()).toEqual('3');
    });
});

5、执行自动化测试

终端输入命令直接执行脚本

protractor conf.js

失败结果:

成功结果:

在实际情况中,自动化测试的逻辑会很复杂。

为了脚本的可维护性,我们把页面功能和测试用例分开来写

// 页面功能
function baidu() { 
    this.open = function () {
        browser.waitForAngularEnabled(false);
        return browser.driver.get('https://www.baidu.com');
    };
    this.getSearchInput = function () {
        return $('#kw');
    };
    this.getSubmitBtn = function () {
        return $('#su');
    };
    this.getResults = async function () {
        await browser.wait(ExpectedConditions.presenceOf($('.result.c-container h3')), 5000);
        return $$('.result.c-container h3 a'); //可直接返回该标签下面的子标签
    };
}

// 测试用例
describe('测试百度搜索', function () {
    it('测试protractor官网会不会出现在第一个搜索结果中', async function () {
        var page = new baidu();
        await page.open();

        await page.getSearchInput().sendKeys('protractor');
        await page.getSubmitBtn().click();

        var searchResults = await page.getResults();
        var firstResult = await searchResults[0].getText();
        expect(firstResult).toBe('Protractor - end-to-end testing for AngularJS');
    });
});

这么写代码,function baidu()这块代码就可以复用了

例如要测试十个关键词的搜索结果,怎么找搜索框,怎么获取结果这些逻辑我们都能复用。
以后页面结构修改,例如搜索框的id变了,我们也只用改一个地方。

另外也可以看出测试用例(describe部分)可读性更强了。

后面还可以再进一步,把function baidu()移到单独的文件中。

三、protractor实例与browser对象

关于测试:protractor实例与浏览器 | 码农家园

1、ProtractorBrowser对象

1.1 browser.angularAppRoot(value)

用于查找Angular元素的css选择器。这通常是“body”,但如果你的ng-app是在页面的子元素,它可能是* a子元素。

1.2 browser.waitForAngularEnabled(boolean)

 如果设置为false,量角器将不会等待Angular $http和Stimeout任务完成后才与浏览器交互。这可能会导致不可靠的测试,但如果你的应用程序连续轮询一个带有$timeout的API,就应该使用。默认为true

1.3 browser.getProcessedConfig( )

获取当前正在运行的已处理配置对象。这将包含当前运行器实例的规格和功能、属性。由跑者设定。

1.4 browser.forkNewDriverInstance()

1.5 browser.restart()

1.6  browser.restartSync()

1.7 browser.useAllAngular2AppRoots(value)

1.8 browser.waitForAngular()

1.9 browser.driver.findElement(locator)

1.10  browser.driver.findElements(locator)

1.11  browser.addMockModule()

1.12  browser.clearMockModules()

1.13 browser.removeMockModule()

1.14 browser.getRegisteredMockModules()

 1.15 browser.driver.get()

1.16 browser.refresh()

1.17 browser.driver.navigate()

浏览器导航

1.18 browser.setLocation()

1.19  browser.controlFlowIsEnabled(boolean)

2、webdriver.WebDriver

Protractor的浏览器对象是selenium-webdriver WebDriver的包装器。它继承了WebDriver的方法调用,但这里只记录了对量角器用户最有用的方法

2.1 browser.actions()

2.2 browser.touchActions()

2.3 browser.executeScript()

2.4 browser.call()

2.5 browser.wait()

2.6 browser.sleep()

2,7 browser.getPageSource()

2.8 browser.close()

2.9 browser.getCurrentUrl()

2.10 browser.getTitle()

2.11   browser.takeScreenshot()

2.12 browser.switchTo()

必须要加getWebElement()方法,否则回内存溢出

 TypeScript browser.switchTo方法代码示例 - 纯净天空

Using Protractor: Switch to iframe using browser.switchTo().frame | 易学教程

2.13 browser.quit()

关闭浏览器

3、常见浏览器操作

3.1 浏览器刷新

browser.driver.navigate().refresh();

3.2 鼠标悬停操作

browser.actions().mouseMove(element).perform();

3.3 浏览器最大化

browser.driver.manage().window().maximize();

3.4 定义页面加载超时时间

browser.manage().timeouts().pageLoadTimeout(120000);  12秒

3.5 定义隐式等待,等待页面加载超时

browser.manage().timeouts().implicitlyWait(180000);  18秒

四、ElementFinder和ElementArrayFinder对象

element(locator)和ptor.findElement(locator)和browser.driver.findElement(locator)

   element(locator) 是 Protractor 中用于查找单个元素的新语法,它会返回一个被封装为 Promise 对象的 ElementFinder 对象locator 参数可以是 CSS 选择器、模型绑定、指令等。在使用 element(locator) 时,Protractor 会自动等待页面上至少存在一个与 locator 匹配的元素,并返回一个 ElementFinder 对象,我们可以使用 click()sendKeys()getText() 等方法对这个元素进行操作。

   browser.driver.findElement(locator) 是 WebDriver 中用于查找单个元素的方法,它会返回一个原生的 WebElement 对象,而不是被封装为 Promise 对象的 ElementFinder 对象。locator 参数同样可以是 CSS 选择器、XPATH 等

        需要注意的是,element(locator)browser.driver.findElement(locator) 的主要区别在于返回值的类型和行为,前者返回的是被封装为 Promise 对象的 ElementFinder 对象,可以使用 Promise 的链式调用语法进行操作;而后者返回的是原生的 WebElement 对象,需要直接调用其方法进行操作。此外,element(locator) 还会自动等待页面上的元素出现,而 browser.driver.findElement(locator) 则需要手动添加等待逻辑。

   ptor.findElement(locator),ptor 是 Protractor 中的全局变量,它表示当前的 WebDriver 实例,我们可以使用 ptor.findElement(locator) 来查找页面上的单个元素。locator 参数可以是 CSS 选择器、XPATH 表达式、模型绑定、指令等

        需要注意的是,ptor.findElement(locator) 在 Protractor 中已经被 element(locator)$() 等方法所替代,这些方法返回的是被封装为 Promise 对象的 ElementFinder 对象,可以使用 Promise 的链式调用语法进行操作。因此,在编写 Protractor 测试时,建议使用 element(locator)$() 等方法来查找页面上的元素,而不是使用 ptor.findElement(locator)

1、ElementFinder对象

        ElementFinder对象是ElementArrayFinder的单个元素。因此,可以使用ElementFinder完成的任何事情,也可以使用一个 ElementArrayFinder。在大多数情况下,ElementFinder可以被视为一个WebElement,特别是,你可以像对待WebElement一样对它们执行操作(click,getText)。在ElementFinder上执行操作后,可以使用then方法访问链的最新结果。与WebElement不同的是ElementFinder将等待angular在执行查找或操作之前解决问题。ElementFinder可用于构建用于查找元素的定位器链。在调用操作之前,ElementFinder不会实际尝试查找元素,这意味着可以在页面可用之前在帮助文件中设置它们

ElementFinder对象不会返回promise对象

1.1 ElementFinder对象的方法 element(locator)

以下所有方法均要跟在  element.(locator).  之后执行

$(locator)是element(locator)的简单方法,但是只能用于css定位,相当于element(by.css(元素定位))

1、clone()

创建ElementFinder对象的浅拷贝

it('test clone()', () => {     
        var ele = element(by.id('username'));
        console.log(ele.clone());
    });

2、locator()

默认返回ElementFinder对象的定位器

it('test locator()', () => {     
        var ele = element(by.id('username'));
        console.log(ele.locator());
    });

3、getWebElement()

返回由这个ElementFinder表示的WebElement。如果元素不存在,抛出WebDriver错误。 属ElementFinder.prototype.getWebElement原型定义方法

it('test locator()', () => {     
        var ele = element(by.id('username'));
        console.log(ele.getWebElement());
    });
//以下四种表达是等价的
$('.parent').getWebElement();
element(by.css('.parent')).getWebElement();
browser.driver.findElement(by.css('.parent'));
browser.findElement(by.css('.parent'));

4、all(sublocator)

可以用来查找当前对象下,所有符合定位器的子元素,返回一个ElementArrayFinder对象,属ElementFinder.prototype.all原型定义方法

5、element(sublocator)

可以用来查找当前对象下,所有符合定位器的子元素,返回一个ElementFinder对象,属ElementFinder.prototype.element原型定义方法

6、$$(sublocator)

和all用法一致,可以用来查找当前对象下,所有符合定位器的子元素,返回一个ElementArrayFinder对象,属ElementFinder.prototype.$$原型定义方法

7、$(sublocator)

用法和element一致,可以用来查找当前对象下,所有符合定位器的子元素,返回一个ElementFinder对象,属ElementFinder.prototype.$原型定义方法

8、isPresent()

确定元素是否出现在页面上,返回true或false

9、isElementPresent(sublocator)

确定当前元素对象的子元素是否存在,而不是当前元素,返回true或false

10、evaluate(string)

可以执行当前元素对象中的JavaScript代码,返回一个ElementFinder对象

 

11、allowAnimations(boolean)

确定当前元素对象上是否允许动画,返回一个ElementFinder对象

12、equals(ElementFinder | webdriver.WebElement)

比较两个元素是否相等,返回promise对象

it('test locator()', () => {     
        var ele = element(by.id('username'));
        console.log(ele.equals(ele));
    });

 

以下方法均继承与selenium.webdriver.WebElement类

13、getWebElement().getDriver()

获取此web元素的父web元素。返回该元素对象的父级driver

14、getWebElement().getId()

•获取此web元素的WebDriver ID字符串表示。返回WebElement.id

15、getWebElement().findElement()

相当于element(locator)方法,但是返回一个WebElement对象

16、click()

点击操作,返回一个promise对象

17、sendKeys(string)

可以对元素对象进行输入,键盘操作和上传文件。返回一个promise对象

it('test locator()', () => {     
        var ele = element(by.id('username'));
        ele.sendKeys("123");
        browser.sleep(2000);
        ele.sendKeys(protractor.Key.CONTROL, "a");
        browser.sleep(2000);
        ele.sendKeys(protractor.Key.NULL);
        browser.sleep(2000);
    });

18、getTagName()

获取元素对象的html标签名,返回一个promise对象

19、getCssValue(cssStyleProperty: string)

获取元素对象的css属性值,返回一个promise对象

20、getAttribute(attributeName: string)

获取元素对象的属性值,返回一个promise对象

21、getText()

获取该元素(包括子元素)的可见innerText,不包含任何前导或尾随空格,可见元素不会被CSS隐藏,返回一个promise对象

22、getSize()

计算该元素对象的包围框的大小(以像素为单位)。返回一个promise对象

23、getLocation()

获取该元素对象在页空间中的位置(坐标)。返回一个promise对象

24、isEnabled()

查询由该实例表示的DOM元素对象是否启用(由disabled属性指定)。返回一个promise对象,true或false

25、isSelected()

查询该元素对象是否被选中。返回一个promise对象,true或false

26、submit()

提交包含此元素(如果是form元素则为此元素)的表单。如果表单中不包含元素,则此命令为no-op。返回一个promise对象

27、clear()

清除此元素对象的值。如果底层DOM元素既不是文本INPUT元素也不是TEXTAREA元素,则此命令无效。返回一个promise对象

28、isDisplayed()

测试当前是否显示此元素对象。返回一个promise对象,true或false

29、takeScreenshot()

.截取该元素边框所包含的可见区域的截图。返回一个promise对象

 2、ElementArrayFinder对象

        ElementArrayFinder用于对元素数组(而不是单个元素)进行操作。ElementArrayFinder用于设置识别元素数组的条件链。特别地,你可以调用all(locator)和filter(filterFn)来返回一个由条件修改的新的ElementArrayFinder,你可以调用get(index)来返回一个位于'index'位置的ElementFinder。类似于jquery, ElementArrayFinder将搜索DOM的所有分支以找到满足条件的元素(即all, filter, get)。然而,在调用操作之前,ElementArrayFinder不会实际检索元素,这意味着它可以在页面可用之前在helper文件(即页面对象)中设置,并在页面更改时重用。在大多数情况下,你可以将ElementArrayFinder视为WebElements数组,特别是,你可以像对待WebElements数组一样对它们执行操作(即click,getText)。该操作将应用于ElementArrayFinder标识的每个元素。

        ElementArrayFinder扩展了Promise,一旦在ElementArrayFinder上执行了一个操作,就可以使用then访问最新的结果,并将作为结果数组返回;数组的长度等于ElementArrayFinder找到的元素的长度,每个结果表示对元素执行操作的结果。

        与WebElement不同的是ElementArrayFinder将等待angular应用程序在执行查找或操作之前解决问题。

ElementArrayFinder对象会返回promise

2.1 ElementArrayFinder对象的方法 element.all(locator)

以下所有方法均要跟在  element.all(locator).  之后执行

$$(cssSelector)是element.all(locator)的简单方法,但是只能用于css定位,相当于element.all(by.css(元素定位))

1、clone()

创建ElementArrayFinder对象的浅拷贝,返回ElementArrayFinder对象

2、all(sublocator)

        可以将对ElementArrayFinder的调用链接起来,以这个ElementArrayFinder中的当前元素为起点来查找一个元素数组。这个函数返回一个新的ElementArrayFinder,它将包含找到的子元素(也可以为空)。

3、filter(callback)

对ElementArrayFinder中的每个元素应用一个筛选函数。返回一个新ElementArrayFinder,其中包含所有通过筛选函数的元素。filter函数接收ElementFinder作为第一个参数,索引作为第二个参数。这实际上并不检索底层元素列表,因此可以在页面对象中使用。

4、get(index: number)

通过索引获取ElementArrayFinder中的一个元素。正数从o开始,从左向右;负数从-1开始,从右向左,(即-i表示从last开始的第i个元素)这并不实际检索底层元素。返回一个ElementFinder对象

 5、first()

获取ElementArrayFinder的第一个匹配元素。这实际上并不检索底层元素。返回一个ElementFinder对象

6、last()

获取ElementArrayFinder的最后一个匹配元素。这实际上并不检索底层元素。返回一个ElementFinder对象

7、count()

计算由ElementArrayFinder表示的元素数量。返回一个promise对象

8、isPresent()

如果存在与查找器匹配的元素,则返回true。返回一个promise对象,true或false

9、locator()

返回该元素对象的定位器

10、then(thenFunction)

根据ElementArrayFinder返回的promise可以进一步处理,返回一个promise对象

11、each(eachFunction)

 调用由ElementArrayFinder表示的每个ElementFinder上的输入函数。返回promise对象

12、map(mapFunction)

对ElementArrayFinder中的每个元素应用一个map函数。回调函数接收ElementFinder作为第一个参数,索引作为第二个参数。返回promise对象

13、reduce(reduceFn)

对累加器(accumulator)和使用定位器找到的每个元素应用reduce函数(从左到右)。reduce函数必须将每个元素还原为单个值(累加器)。返回累加器的promise。reduce函数分别接收累加器、当前ElementFinder、索引和整个ElementFinder数组。

14、evaluate(expression: string)

可以执行当前元素对象中的JavaScript代码,返回一个ElementArrayFinder对象

15、allowAnimations(boolean)

确定当前元素对象上是否允许动画,返回一个ElementArrayFinder对象

五、 Protractor Locators

Locators 定位器_adrianna_xy的博客-CSDN博客

protractor中元素定位方式_protractor的元素定位_weixin_39430584的博客-CSDN博客

在webdiver.By的基础上扩展,形成了ProtractorBy

1、ProtractorBy

1.1 by.addLocator(locatorName, functionOrScript)

自定义选择器

1.2 by.binding

通过文本绑定查找元素。可以部分匹配,因此任何绑定到包含输入字符串的变量的元素将被返回,返回ProtractorLocator

1.3 by.exactBinding

通过精确绑定找到一个元素。必须输入全部属性,不能是部分的,返回ProtractorLocator

1.4 by.model

通过ng-model表达式找到一个元素。返回ProtractorLocator

1.5 by.buttonText

通过全部文本找到一个按钮,返回ProtractorLocator

1.6 by.partialButtonText

通过部分文本找到一个按钮,返回ProtractorLocator

1.7 by.repeater

找到ng-repeat中的元素。返回ProtractorLocator

1.8 by.exactRepeater

 通过全部的ng-repeat属性值定位元素,返回ProtractorLocator

1.9 by.cssContainingText

通过CSS查找包含特定字符串的元素。返回ProtractorLocator

1.10  by.options

通过ng-options表达式找到一个元素。返回ProtractorLocator

1.11 by.deepCss

在Shadow DOM中通过css选择器找到一个元素。返回Locator

 

2、 webdiver.By

2.1 by.className

2.2 by.css

2.3 by.id

 2.4 by.linkText

2.5  by.js(expression)

2.6 by.name

2.7 by.partialLinkText

2.8 by.tagName

2.9 by.xpath

 六、ExpectedConditions(预期条件)

表示对protractor封装的预期条件库,特别是在处理non-angula应用程序时。每个条件返回一个求值为promise的函数。您可以使用and, or, and/or not混合多个条件。还可以将这些条件与所写的任何其他条件混合使用。

1、ExpectedConditions.not

对promise的结果取反。返回一个!function 函数表达式

2、ExpectedConditions.and

使用   逻辑与  连接许多预期条件,只要有一个为false则为false。返回一个!function 函数表达式

3、ExpectedConditions.or

使用   逻辑或  连接许多预期条件,只要有一个为true则为true。返回一个!function 函数表达式

4、ExpectedConditions.alertIsPresent

预计会出现一个警报。

5、ExpectedConditions.elementToBeClickable

检查元素的期望可见并启用,以便可以单击它。

6、ExpectedConditions.textToBePresentInElement

检查元素中是否存在给定文本的期望。如果elementFinder没有找到元素,则返回false。

7、ExpectedConditions.textToBePresentInElementValue

用于检查元素值中是否存在给定文本的期望。如果elementFinder没有找到元素,则返回false。

8、ExpectedConditions.titleContains

检查标题是否包含区分大小写的子字符串的期望。

9、ExpectedConditions.titleIs

检查页面标题的期望。

10、ExpectedConditions.presenceOf

.用于检查一个元素是否出现在页面的DOM中。这并不一定意味着元素是可见的。

11、ExpectedConditions.stalenessOf

一个期望的条件,返回一个表示元素是否过期的promise。

12、ExpectedConditions.visibilityOf

用于检查元素是否出现在页面的DOM中且是否可见的期望。可见性意味着元素不仅被显示,而且其高度和宽度都大于o。这与invisiityof相反。

13、ExpectedConditions.invisibilityOf

用于检查元素是否出现在页面的DOM中且是否不可见的期望。

14、ExpectedConditions.elementToBeSelected

选中了检查选择的期望。

七、protractor 断言

expect:断言表达式

  1. 每个测试文件中可以包含多个 describe.
  2. 每个 describe 中可以包含多个 it.
  3. 每个 it 中可以包含多个 expect.
  4. describe 可嵌套使用.

1、toBe

基本类型判断

it("The 'toBe' matcher compares with ===", function() {
  var a = 12;
  var b = a;
  expect(a).toBe(b);
  expect(a).not.toBe(null);
});

2、toEqual

除了能判断基本类型(相当于”toBe”),还能判断对象

it("should work for objects", function() {
  var foo = {
    "a": 12,
    "b": 34
  };
  var bar = {
    "a": 12,
    "b": 34
  };
  expect(foo).toEqual(bar);
});

3、toMatch

使用正则表达式判断

it("The 'toMatch' matcher is for regular expressions", function() {
  var message = "foo bar baz";
  expect(message).toMatch(/bar/);
  expect(message).toMatch("bar");
  expect(message).not.toMatch(/quux/);
});

4、toBeDefined

判断是否定义

it("The 'toBeDefined' matcher compares against 'undefined'", function() {
  var a = {
    "foo": "foo"
  };
  expect(a.foo).toBeDefined();
  expect(a.bar).not.toBeDefined();
});

5、toBeUndefined

判断是否是 undefined,与”toBeDefined”相反

it("The 'toBeUndefined' matcher compares against 'undefined'", function() {
  var a = {
    "foo": "foo"
  };
  expect(a.foo).not.toBeUndefined();
  expect(a.bar).toBeUndefined();
});

6、toBeNull

判断是否为 null

it("The 'toBeNull' matcher compares against null", function() {
  var a = null;
  var foo = "foo";
  expect(null).toBeNull();
  expect(a).toBeNull();
  expect(foo).not.toBeNull();
});

7、toBeTruthy

判断是否是 true

it("The 'toBeTruthy' matcher is for boolean casting testing", function() {
  var a,
    foo = "foo";
  expect(foo).toBeTruthy();
  expect(a).not.toBeTruthy();
  expect(true).toBeTruthy();
});

8、toBeFalsy

判断是否是 false

it("The 'toBeFalsy' matcher is for boolean casting testing", function() {
  var a,
    foo = "foo";
  expect(a).toBeFalsy();
  expect(foo).not.toBeFalsy();
  expect(false).toBeFalsy();
});

9、toContain

判断数组是否包含(可判断基本类型和对象)

it("The 'toContain' matcher is for finding an item in an Array", function() {
  var a = ["foo", "bar", "baz"];
  var b = [{ "foo": "foo", "bar": "bar" }, { "baz": "baz", "bar": "bar" }];
  expect(a).toContain("bar");
  expect(a).not.toContain("quux");
  expect(b).toContain({ "foo": "foo", "bar": "bar" });
  expect(b).not.toContain({ "foo": "foo", "baz": "baz" });
});

10、toBeLessThan

判断值类型的大小,结果若小则为 True(也可以判断字符及字符串,以 ascii 码的大小为判断依据)

it("The 'toBeLessThan' matcher is for mathematical comparisons", function() {
  var pi = 3.1415926,
    e = 2.78;
  expect(e).toBeLessThan(pi);
  expect(pi).not.toBeLessThan(e);
  expect("a").toBeLessThan("b");
  expect("b").not.toBeLessThan("a");
});

11、toBeGreaterThan

判断值类型的大小,结果若大则为 True,与 toBeLessThan 相反(也可以判断字符及字符串,以 ascii 码的大小为判断依据)

it("The 'toBeGreaterThan' matcher is for mathematical comparisons", function() {
  var pi = 3.1415926,
    e = 2.78;
  expect(pi).toBeGreaterThan(e);
  expect(e).not.toBeGreaterThan(pi);
  expect("a").not.toBeGreaterThan("b");
  expect("b").toBeGreaterThan("a");
});

12、toBeCloseTo

判断数字是否相似(第二个参数为小数精度,默认为 2 位)

it("The 'toBeCloseTo' matcher is for precision math comparison", function() {
  var a = 1.1;
  var b = 1.5;
  var c = 1.455;
  var d = 1.459;
  expect(a).toBeCloseTo(b, 0);
  expect(a).not.toBeCloseTo(c, 1);
  expect(c).toBeCloseTo(d);
});

13、toThrow

判断是否抛出异常

it('', () => {
        const foo = function(){
            throw new TypeError('123');
        }
        expect(foo).toThrow();
    });

14、toThrowError

判断是否抛出了指定的错误

it("The 'toThrowError' matcher is for testing a specific thrown exception", function() {
  var foo = function() {
    throw new TypeError("foo bar baz");
  };
  expect(foo).toThrowError("foo bar baz");
  expect(foo).toThrowError(/bar/);
  expect(foo).toThrowError(TypeError);
  expect(foo).toThrowError(TypeError, "foo bar baz");
});

八、Hook函数

beforeAll

每个 suite(即 describe)中所有 spec(即 it)运行之前运行

beforeEach

每个 spec(即 it)运行之前运行

afterAll

每个 suite(即 describe)中所有 spec(即 it)运行之后运行

afterEach

每个 spec(即 it)运行之后运行
 

var globalCount;
describe("Setup and Teardown suite 1", function() {
  var suiteGlobalCount;
  var eachTestCount;

  beforeAll(function() {
    globalCount = 0;
    suiteGlobalCount = 0;
    eachTestCount = 0;
  });

  afterAll(function() {
    suiteGlobalCount = 0;
  });

  beforeEach(function() {
    globalCount++;
    suiteGlobalCount++;
    eachTestCount++;
  });

  afterEach(function() {
    eachTestCount = 0;
  });

  it("Spec 1", function() {
    expect(globalCount).toBe(1);
    expect(suiteGlobalCount).toBe(1);
    expect(eachTestCount).toBe(1);
  });

  it("Spec 2", function() {
    expect(globalCount).toBe(2);
    expect(suiteGlobalCount).toBe(2);
    expect(eachTestCount).toBe(1);
  });
});

describe("Setup and Teardown suite 2", function() {
  beforeEach(function() {
    globalCount += 2;
  });

  it("Spec 1", function() {
    expect(globalCount).toBe(4);
  });
});

九、jasmine方法

1、jasmine.getEnv().addReporter()

   jasmine.getEnv().addReporter() 是 Jasmine 测试框架中的一个方法,用于向测试环境添加一个自定义的测试报告生成器(reporter)。

        在 Jasmine 中,测试报告生成器负责将测试结果输出到控制台或者其他地方。默认情况下,Jasmine 会使用控制台报告生成器(Console Reporter),将测试结果输出到控制台上。

        但是,在实际应用中,我们可能需要将测试结果输出到其他地方,比如文件、数据库、邮件等。这时候,就可以使用 jasmine.getEnv().addReporter() 方法添加一个自定义的测试报告生成器,来满足特定的需求。

例如,以下代码会向 Jasmine 测试环境添加一个自定义的报告生成器,用于将测试结果输出到文件中:

const fs = require('fs');
const CustomReporter = function () {
  this.specDone = function (result) {
    fs.appendFileSync('test-results.txt', `${result.fullName}: ${result.status}\n`);
  };
};
jasmine.getEnv().addReporter(new CustomReporter());

        上面的代码定义了一个名为 CustomReporter 的自定义测试报告生成器,它会在每个测试用例(it)执行完成后,将测试结果以 fullName: status 的形式输出到 test-results.txt 文件中。然后,将该报告生成器传递给 jasmine.getEnv().addReporter() 方法,就可以将其添加到 Jasmine 测试环境中,让其生效。

实际案例解析:

// Take screenshots for failed expect for Jasmine 2.0
        jasmine.getEnv().addReporter(new function() {
            var originalAddExpectationResult = jasmine.Spec.prototype.addExpectationResult;
            jasmine.Spec.prototype.addExpectationResult = function() {
                if (!arguments[0]) {
                    // take screenshot
                    // this.description and arguments[1].message can be useful to constructing the filename.
                    if (this.description != specDescription) {

                        browser.params.raceTrack.testCaseResult = 'FAIL';
                        specDescription = this.description;

                        //console.log('Screeshot name: ' + this.description.split(' ').join('_'))
                        //console.log("arguments[1].message " + arguments[1].message);
                        //console.log("this.description " + this.description);
                        var screenshotName = this.description.split(' ').join('_');
                        globalUtil.takeScreenshot(screenshotSavePath, screenshotName).then(function() {
                            browser.sleep(5000);
                        }).then(function() {
                            racetrack.uploadScreenshot(screenshotSavePath, screenshotName, "Error Screenshot");
                        }).then(function() {
                            browser.sleep(5000);
                        });
                    }
                }
                return originalAddExpectationResult.apply(this, arguments);
            };
        });

这段代码使用了 Jasmine 测试框架的 addReporter() 方法来添加一个自定义的测试报告生成器。该报告生成器会在每个测试用例执行完成后,检查测试结果是否为失败(即第一个参数为假值),如果是,则会执行一些操作,包括:

  • 截取当前页面的屏幕截图(使用 globalUtil.takeScreenshot() 方法)。
  • 将屏幕截图上传到测试报告管理系统(使用 racetrack.uploadScreenshot() 方法)。
  • 将测试结果标记为失败(修改 browser.params.raceTrack.testCaseResult 变量的值)。

该报告生成器使用了 Jasmine 的 Spec 对象的原型来进行修改。具体来说,它通过保存 jasmine.Spec.prototype.addExpectationResult 方法的原始实现,然后覆盖该方法来实现对测试结果的监控和处理。在覆盖 addExpectationResult() 方法时,它首先检查测试结果是否为失败,如果是,则执行上述操作,然后再调用原始实现。

1、jasmine.Spec.prototype.addExpectationResult方法解析

jasmine.Spec.prototype.addExpectationResult 是 Jasmine 中的一个方法,用于在测试用例执行完毕后向测试报告中添加断言结果。该方法接受两个参数,分别是布尔类型的 passed 和字符串类型的 message,用于表示断言是否通过以及断言的描述信息。

jasmine.Spec.prototype.addExpectationResult 方法有两个参数:

  1. passed:表示测试是否通过的布尔值。
  2. expectationResult:一个对象,包含以下属性:
    • passed: 表示测试是否通过的布尔值。
    • message: 一个字符串,描述测试失败的原因或错误信息。
    • error: 一个 JavaScript Error 对象,表示测试中发生的错误。

在默认情况下,当一个测试用例中的所有断言都通过时,Jasmine 会自动向测试报告中添加一个 “Passed” 的标记。但是,当测试用例中的某个断言未通过时,Jasmine 并不会自动将该测试用例标记为 “Failed”,而是会继续执行其他的断言,并在所有断言执行完毕后才会判断该测试用例是否失败。因此,为了在测试报告中及时反映出测试结果,需要手动调用 addExpectationResult 方法,并在断言未通过时添加相应的逻辑,如下所示:

jasmine.Spec.prototype.addExpectationResult = function(passed, message) {
  if (!passed) {
    // 断言未通过,执行相应的逻辑
  }
  // 调用原始的 addExpectationResult 方法,将断言结果添加到测试报告中
  jasmine.Spec.prototype.addExpectationResult.call(this, passed, message);
};

在这个例子中,我们重写了 jasmine.Spec.prototype.addExpectationResult 方法,当断言未通过时执行相应的逻辑,并调用原始的 addExpectationResult 方法将断言结果添加到测试报告中

JS中通过原型对象重写方法后,原始方法不会被覆盖嘛?

        在 JavaScript 中,通过原型对象重写方法会覆盖原始方法。当对象调用该方法时,会执行原型链上最靠近对象的方法,而不是原始方法。

例如,如果一个对象的原型链上有一个方法 foo,然后在该对象上重写了该方法,那么在调用 foo 方法时,会执行该对象上的方法,而不是原型链上的方法。

这也意味着,如果多个对象共享同一个原型对象,并且其中一个对象重写了一个方法,那么所有对象都会受到影响,它们都将调用重写后的方法。

jasmine.Spec.prototype.addExpectationResult方法重写后,对象会调用哪个?

在 Jasmine 中,每个测试用例都会创建一个 jasmine.Spec 对象,它代表了该测试用例。jasmine.Spec.prototype.addExpectationResult 方法是 jasmine.Spec 对象的原型方法,用于向该测试用例添加期望结果。

当我们重写了 jasmine.Spec.prototype.addExpectationResult 方法后,当测试用例运行时,会执行我们重写的方法。因此,在测试用例执行期间,会调用我们所定义的方法,而不是原始的 jasmine.Spec.prototype.addExpectationResult 方法。

需要注意的是,重写 jasmine.Spec.prototype.addExpectationResult 方法只会影响当前测试用例的期望结果,不会影响其他测试用例。

jasmine.Spec.prototype.addExpectationResult方法重写后,不是覆盖原始方法了吗,为什么还会有原始方法?

在 Jasmine 中,jasmine.Spec.prototype.addExpectationResult 方法是 jasmine.Spec 对象的原型方法,被所有的 jasmine.Spec 对象所共享。当我们重写该方法时,所有的 jasmine.Spec 对象在调用该方法时都会执行我们所定义的方法,而不是原始的 jasmine.Spec.prototype.addExpectationResult 方法。

因此,实际上在重写 jasmine.Spec.prototype.addExpectationResult 方法后,原始的方法已经被覆盖了,不会再被调用。如果我们需要在重写的方法中调用原始的方法,可以使用 originalAddExpectationResult 变量保存原始方法的引用,并在重写的方法中调用它。

2、this.description 解析

在这段代码中,this.description 指的是当前正在执行的测试用例的描述信息。在 Jasmine 中,每个测试用例都有一个描述信息,用于描述该测试用例的目的和功能。例如,下面的代码中,第一个参数 "should add two numbers" 就是该测试用例的描述信息:

describe("Calculator", function() {
  it("should add two numbers", function() {
    // 测试用例的具体实现
  });
});

在重写 jasmine.Spec.prototype.addExpectationResult 方法时,我们可以通过 this.description 获取当前测试用例的描述信息,并将其用于构建截图文件名等操作。如果某个测试用例中的断言未通过,我们也可以通过 this.description 知道是哪个测试用例失败了,从而更方便地定位问题。

3、arguments[0]解析

arguments[0] 指的是 Jasmine Spec 对象中 addExpectationResult 方法的第一个参数,即 pass 标志。如果该参数为 false,表示测试结果失败,那么这段代码将执行截图和上传截图等操作。

4、arguments[1]解析

arguments[1] 指的是 Jasmine Spec 对象中 addExpectationResult 方法的第二个参数,即 expectationResult 对象。expectationResult 对象包含以下属性:

  • passed: 表示测试是否通过的布尔值。
  • message: 一个字符串,描述测试失败的原因或错误信息。
  • error: 一个 JavaScript Error 对象,表示测试中发生的错误。

在这段代码中,arguments[1] 对象被用于获取测试失败的消息,并用于构建截图文件名。

十、代码解析

1、then函数中的return问题

 this.addNfsDatastore = function (StoragePage, EsxuiPage, datastoreName, nfsServer, nfsShare) {

        var newDatastoreWizard = StoragePage.datastoresTab.newDatastoreButton.newDatastoreWizard,
            yesButton;
        //定位新建存储按钮
        return globalUtil.waitForVisibility(StoragePage.datastoresTab.newDatastoreButton.self()).then(function () {
            //点击新建存储按钮
            return StoragePage.datastoresTab.newDatastoreButton.self().takeScreenshotAndClick();
        }).then(function () {
            //定位创建新的VMFS数据存储
            return globalUtil.waitForVisibility(newDatastoreWizard.createNewVMFSdatastore());
        }).then(function () {
            return racetrack.log("- - Select Create new NFS datastore and click next button.");
        }).then(function () {
            //点击挂在NFS数据存储
            return newDatastoreWizard.createNewNfsDatastore().takeScreenshotAndClick();
        }).then(function () {
            //点击下一页按钮
            return newDatastoreWizard.nextButton().takeScreenshotAndClick();
        }).then(function () {
            //定位名称输入框
            return globalUtil.waitForVisibility(newDatastoreWizard.nfsDatastoreName());
        }).then(function () {
            return racetrack.log("- - Enter non-ASCII datastore name: " + datastoreName);
        }).then(function () {
            //输入datastoreName
            return newDatastoreWizard.nfsDatastoreName().sendKeys(datastoreName);
        }).then(function () {
            return racetrack.log("- - Enter NFS server: " + nfsServer);
        }).then(function () {
            //在NFS输入框中输入nfsServer
            return newDatastoreWizard.nfsHost().sendKeys(nfsServer);
        }).then(function () {
            return racetrack.log("- - Enter NFS share: " + nfsShare);
        }).then(function () {
            //NFS共享输入框中输入nfsShare
            return newDatastoreWizard.nfsShare().sendKeys(nfsShare);
        }).then(function () {
            //点击下一页按钮
            return newDatastoreWizard.nextButton().takeScreenshotAndClick();
        }).then(function () {
            return racetrack.log("- - Click Finish to add non-ASCII datastore.");
        }).then(function () {
            return globalUtil.waitForVisibility(newDatastoreWizard.NFSversionLable());   //modify
        }).then(function () {
            //定位完成按钮
            return globalUtil.waitForVisibility(newDatastoreWizard.finishButton());
        }).then(function () {
            //点击完成按钮
            return newDatastoreWizard.finishButton().takeScreenshotAndClick();
        }).then(function () {
            return esxuiUtil.dismissAlert(EsxuiPage);
        }).then(function () {
            return browser.sleep(Timeout.WAIT_FOR_STORAGE_ACTION);
        })

    };

这段代码是一个 Protractor 测试用例中的一个函数,函数的功能是在 vSphere Web 客户端上添加一个新的 NFS 数据存储。

函数中首先定义了一些变量,然后使用 globalUtil.waitForVisibility() 函数等待新建存储按钮可见,接着点击该按钮,进入新建存储向导的第一个页面。

函数中的后续步骤依次执行以下操作:

  • 点击“创建新的NFS数据存储”选项。
  • 点击“下一页”按钮。
  • 输入数据存储的名称、NFS服务器和共享路径。
  • 点击“下一页”按钮。
  • 点击“完成”按钮以完成存储的创建。
  • 等待一个警告对话框出现并关闭它。
  • 等待一段时间,让存储创建完成。

在函数中,使用了 takeScreenshotAndClick()sendKeys() 函数来模拟用户在 Web 页面上的交互操作,使用了 waitForVisibility() 函数来等待某些元素在页面上可见后再执行后续的操作。

此外,函数中还使用了一个 racetrack.log() 函数来记录日志,以便在测试失败时能够追踪问题。

then函数中必须使用return嘛

        在这段代码中,使用了 then() 函数来链接多个 Promise,每个 then() 函数接收上一个 Promise 的返回值并返回一个新的 Promise 对象。当你在 then() 函数中执行异步操作时,你需要返回一个 Promise 对象,以便在 Promise 链中继续使用 then() 函数。

        因此,如果你在 then() 函数中使用了异步操作(比如 takeScreenshotAndClick()sendKeys()),那么你需要在该函数的末尾使用 return 关键字来返回 Promise 对象。如果你不使用 return,则 Promise 链会中断,后续的 then() 函数将无法接收到前一个 Promise 的返回值,也无法继续执行 Promise 链中的操作。

        如果你在 then() 函数中没有使用异步操作,那么你可以省略 return 关键字,这不会影响 Promise 链的执行。

then函数自身不会返回promise嘛,还要用return返回

        你说得没错,then() 函数本身不会返回当前异步操作后新增加的Promise,而是返回一个承接前一个then方法返回的 Promise 对象,以便在 Promise 链中继续使用 then() 函数。

        相当于一张白纸,每进行一次异步操作,就会在白纸上做个标记,然后由后续的then方法在进行链式操作。

then() 函数中,如果你执行了一个异步操作(比如网络请求、定时器、读写文件等),你需要在异步操作完成后返回一个 Promise 对象,以便在下一个 then() 函数中继续执行。如果你没有返回一个 Promise 对象,后续的 then() 函数将会在当前的 Promise 状态(fulfilled 或 rejected)下立即执行,而不是等待异步操作完成后再执行

因此,在 then() 函数中,如果你执行了异步操作,你需要使用 return 关键字来返回 Promise 对象,以便在 Promise 链中继续执行。如果你没有执行异步操作,你可以省略 return 关键字,因为 then() 函数会自动返回一个 Promise 对象。

因此,Promise 对象是 JavaScript 中用于处理异步操作的一种机制,而 Promise 是这种机制中的核心对象。Promise 对象可以通过调用 new Promise() 来创建,它具有 then()catch()finally() 等方法。

2、angularJS文本元素value属性

expect(element(by.model('vm.notes')).getAttribute('value')).toEqual(browser.params.i18n.string)

通过该定位器element(by.model('vm.notes'))找到的元素,没有value属性值,为什么还能获取器value属性值

        定位器 element(by.model('vm.notes')) 是用来获取一个 AngularJS 应用程序中绑定到模型 vm.notes 的元素,它返回的是一个 ElementFinder 对象,这个对象包装了页面中匹配到的单个元素,并提供了许多方法来与该元素进行交互。

        在这种情况下,element(by.model('vm.notes')) 返回的元素是一个输入框或文本域等可以输入文本内容的控件。而这些控件通常不是通过 value 属性来存储其文本内容的,而是通过其它属性或属性值来实现文本内容的存储和获取。比如在 AngularJS 中,通常使用 ng-model 指令来绑定一个模型和一个控件,模型的值会被存储在内部的 $$ngModelValue 属性中。

        因此,虽然通过 element(by.model('vm.notes')) 找到的元素没有 value 属性,但是它可能有其它属性或方法可以获取其文本内容,比如上面提到的 $$ngModelValue 属性。在这段代码中,notes.getAttribute('value') 实际上是调用了 getAttribute() 方法来获取元素的 value 属性值,但是由于该元素没有 value 属性,因此该方法返回了 nullundefined。然后,使用 expect() 函数将其与预期值比较时,会将 nullundefined 转换为字符串类型的 'null''undefined',然后再进行比较,所以即使没有 value 属性,也可以获取其文本内容。

3、input元素清空问题

解决方式一:

        在使用Protractor中的clear()方法清空一个input元素的值时,有时会发现该方法无效。这通常是因为Protractor在执行clear()方法之前尝试发送了一些按键事件,例如backspace键和delete键,以确保清空输入框的内容。

        如果在clear()方法执行之前,输入框中已经有了一些文本,而这些文本中包含了一些特殊字符或者HTML标记,那么这些按键事件可能会无法正确地删除这些特殊字符或HTML标记,导致输入框内容清空不完全。

为了解决这个问题,可以使用Javascript的executeScript方法来清空输入框的值。例如:

var inputBox = element(by.css('#myInputBox'));
browser.executeScript('arguments[0].value = ""', inputBox.getWebElement());

这段代码使用Protractor来定位一个id为myInputBoxinput元素,并使用executeScript方法来执行一段Javascript代码,将该input元素的值设置为空字符串,从而实现清空该输入框的值的功能。

具体来说,这段代码的执行流程如下:

  1. element(by.css('#myInputBox'))用于定位idmyInputBox的元素,并返回一个ElementFinder对象。

  2. inputBox.getWebElement()用于获取该ElementFinder对象所代表的input元素的底层WebElement对象。

  3. browser.executeScript('arguments[0].value = ""', inputBox.getWebElement())用于执行一段Javascript代码,该代码将输入框的value属性设置为空字符串。在这里,arguments[0]代表传递给Javascript代码的第一个参数,也就是获取到的input元素的WebElement对象。

        通过这种方式,即使input元素中包含有特殊字符或者HTML标记等,也能够成功清空输入框的内容。同时,该方法还可以在input元素已经被禁用或只读的情况下正常工作。

解决方式二:

如果即使使用了上述方法,clear()和Javascript的executeScript方法都无法成功清空输入框的内容,那么可能是由于以下原因之一:

  1. 输入框已被禁用或只读。在这种情况下,无论是使用clear()方法还是Javascript的executeScript方法都无法清空输入框的值。

  2. 页面中存在一些Javascript代码或事件处理程序,它们可能会在clear()方法执行之后再次设置输入框的值,导致输入框内容无法清空。这种情况下,可以尝试在clear()方法之后加入一个小的延迟,以确保页面上的所有事件处理程序都已执行完毕。例如:

var inputBox = element(by.css('#myInputBox'));
inputBox.clear().then(function() {
  browser.sleep(500);
});

这段代码将在调用clear()方法之后等待500毫秒,以确保所有事件处理程序都已执行完毕。

  1. 可能是由于页面中存在多个相同的input元素,而Protractor选择了错误的元素进行操作,导致无法清空输入框的内容。在这种情况下,可以尝试使用不同的选择器或索引来定位正确的输入框元素。

十一、protractor生成报告

protractor 添加测试报告_protractor 测试报告_过客的停留处的博客-CSDN博客

关于angularjs:protractor使用jasmine报告器测试报告 | 码农家园

Protractor-编写第一个测试 - 芒果文档

十二、命令执行protractor

动态替换configuration中的参数

案例

拓展知识

1、变量名前加下划线

JavaScript中方法或者变量名称前加下划线的是什么意思?_方法前面添加__MakeGreatEffort的博客-CSDN博客

2、使用browser.method()和browser.method()方法区别

量角器:使用 browser 还是 browser.driver 方法? - IT屋-程序员软件开发技术分享社区

3、同步、异步、阻塞、非阻塞

同步(Synchronous)异步(Asynchronous) 阻塞(Blocking)和非阻塞(Non-blocking)的概念_zq_1230123的博客-CSDN博客

4、protractor核心API

Protractor-核心APIS - 芒果文档

5、多级路径表示

好用的路径表示 /**/*.*_xiaye_go的博客-CSDN博客

6、JS中的立即执行函数

https://www.cnblogs.com/yangxianyang/p/13675566.html

7、浏览器w3c标准

Web 标准 | 菜鸟教程

在Protractor中,设置'w3c': false的意思是禁用浏览器的W3C标准Webdriver协议。

        W3C标准Webdriver协议是浏览器自动化测试中的一种协议,用于控制和操作浏览器的行为。但是,在某些情况下,W3C标准Webdriver协议可能会导致一些问题,例如在与某些浏览器驱动程序(例如Safari)一起使用时可能会出现问题。

        因此,Protractor提供了一个选项来禁用W3C标准Webdriver协议。通过设置'w3c': falseProtractor将使用旧版的Selenium Webdriver协议来控制浏览器的行为,这可能会更加稳定和可靠。

        需要注意的是,禁用W3C标准Webdriver协议可能会导致某些浏览器特定的功能不可用,或者无法使用一些最新的Web技术。因此,应谨慎使用此选项,并根据实际情况进行评估。

为什么设置了这个'w3c': false就会报错

        在Protractor中,'w3c': false是一个配置项,用于将WebDriver连接到非W3C兼容的浏览器。如果设置了此配置项,但连接的浏览器是W3C兼容的浏览器,则可能会导致错误。

        W3C是一个Web标准组织,定期发布用于Web浏览器和WebDriver的标准。W3C WebDriver是一种用于控制Web浏览器的协议,但是并非所有的浏览器都完全符合该协议。因此,如果您连接到一个不兼容W3C的浏览器,则需要使用'w3c': false配置项来告诉Protractor使用非W3C的协议进行通信。

        然而,如果您设置了'w3c': false,但连接到的浏览器是W3C兼容的,则Protractor会尝试使用非W3C的协议进行通信,这可能导致错误。因此,如果您连接到的浏览器是W3C兼容的,最好不要设置'w3c': false配置项。

        如果您遇到了与'w3c': false相关的错误,请尝试将其删除或将其设置为'w3c': true,并查看是否可以解决问题。

8、远程服务

selenium运行提示DevTools listening on ws://127.0.0.1:55960/devtools/browser/9e6a07ea-689c-4b3b-8bcf-a3283a303c31,是什么意思

        这是Selenium在使用Chrome或者Chromium浏览器时启动了一个远程调试服务,使得Selenium可以通过该服务与浏览器进行交互。在启动该服务后,Selenium会输出类似于"DevTools listening on ws://127.0.0.1:55960/devtools/browser/9e6a07ea-689c-4b3b-8bcf-a3283a303c31"的信息,其中"ws://127.0.0.1:55960"表示远程调试服务的地址,"9e6a07ea-689c-4b3b-8bcf-a3283a303c31"表示浏览器的标识符,通过该标识符可以在多个浏览器实例中区分不同的浏览器。

设置了这个参数directConnect: true,为什么还会启动远程服务

        在使用Protractor进行端到端测试时,如果设置了directConnect: true,则Protractor会尝试直接连接到浏览器而不是使用远程WebDriver服务。这通常可以提高测试的执行速度和稳定性。

        然而,即使使用了directConnect: true,Selenium WebDriver仍然需要启动Chrome或者Firefox浏览器的一个实例,并与该实例建立通信。在这种情况下,Selenium WebDriver会使用Chrome或Firefox的驱动程序来启动浏览器实例,并将驱动程序的地址设置为本地地址(localhost)。

        因此,即使使用了directConnect: true,在运行测试之前,仍然需要启动Chrome或者Firefox浏览器的一个实例,并将该浏览器实例与Selenium WebDriver进行通信。这就是为什么你在运行测试时仍然会看到浏览器被启动,并且会出现远程服务的提示。

什么是WebDriver实例 

        WebDriver 实例是 WebDriver 客户端库通过连接到 WebDriver 服务器创建的一个对象,用于控制特定浏览器的自动化测试任务。通过调用客户端库提供的方法,您可以使用 WebDriver 实例来模拟用户在浏览器中的操作,如打开网页、点击元素、输入文本、提交表单等。WebDriver 实例负责将您的测试脚本翻译为浏览器可以执行的命令,并将执行结果返回给客户端库,以便您进行进一步的操作或断言。通常情况下,您可以使用单个 WebDriver 实例执行一个或多个测试用例。当您完成测试任务后,可以调用客户端库提供的方法来关闭浏览器并断开与 WebDriver 服务器的连接。 

selenium为什么要使用使用远程WebDriver服务尼

        Selenium可以使用远程WebDriver服务来控制多个不同的浏览器和平台进行测试。通过使用远程WebDriver服务,可以将测试脚本和浏览器分别运行在不同的计算机上,这样可以在分布式环境下并行运行多个测试,从而提高测试效率。

        在使用远程WebDriver服务时,测试脚本和WebDriver客户端(例如Selenium WebDriver)运行在同一台计算机上,而WebDriver服务器则运行在另一台计算机上,该服务器负责将测试命令发送到浏览器并返回执行结果。这种模式下,测试脚本通过与远程WebDriver服务进行通信来控制浏览器的行为。

        此外,远程WebDriver服务还可以在不同的浏览器和平台之间提供互操作性。例如,可以在一个计算机上运行测试脚本并将命令发送到远程WebDriver服务,该服务将命令发送到远程服务器上运行的不同浏览器,这可以在同一个测试套件中进行多个浏览器和平台的测试。

        总之,使用远程WebDriver服务可以提高测试效率和可维护性,并且可以方便地进行分布式测试和跨浏览器测试。

什么是WebDriver客户端

WebDriver客户端是一个与WebDriver服务器进行通信的客户端库,它提供了一组方法和接口,用于编写自动化测试脚本。常见的WebDriver客户端库有Java、Python、JavaScript等,例如Java中的Selenium WebDriver、Python中的selenium、JavaScript中的webdriver.io等。

WebDriver客户端库通常提供以下功能:

  1. 与WebDriver服务器进行通信,将测试命令发送到远程浏览器并接收执行结果。

  2. 操作浏览器,例如模拟用户行为、填充表单、点击链接、截图等。

  3. 获取浏览器信息,例如获取页面源代码、获取元素属性、获取浏览器版本号等。

使用WebDriver客户端可以方便地编写自动化测试脚本,使测试脚本的编写更加高效和简单。此外,WebDriver客户端还可以与多种测试框架(例如TestNG、JUnit、Mocha等)和持续集成工具(例如Jenkins、Travis CI等)进行集成,以便在不同的测试环境中运行测试。

什么是WebDriver服务器

WebDriver服务器是一个远程服务,它接收来自客户端的请求,然后将请求发送到指定的浏览器,并将执行结果返回给客户端。简单来说,WebDriver服务器是连接自动化测试脚本和浏览器的中间件。

WebDriver服务器的主要功能包括:

  1. 接收来自客户端的请求,例如打开浏览器、访问URL、执行JavaScript代码等。

  2. 将请求发送到浏览器,例如Chrome、Firefox等。

  3. 接收浏览器的执行结果,并将结果返回给客户端。

在Selenium中,WebDriver服务器是通过启动浏览器驱动程序来实现的。例如,ChromeDriver是一个WebDriver服务器,它将客户端的请求发送到Chrome浏览器,并将执行结果返回给客户端。当自动化测试脚本通过WebDriver客户端库发送命令时,WebDriver客户端库将命令发送到WebDriver服务器,WebDriver服务器再将命令发送到浏览器,并将执行结果返回给WebDriver客户端库,最终由测试脚本进行处理。

ChromeDriver是一个WebDriver服务器吗

        是的,ChromeDriver是一个WebDriver服务器,它是连接自动化测试脚本和Chrome浏览器的中间件。ChromeDriver可以接收来自Selenium WebDriver客户端的命令,并将这些命令转换成Chrome浏览器可以理解的指令,然后将这些指令发送给Chrome浏览器进行执行。ChromeDriver还能接收Chrome浏览器的执行结果,并将这些结果发送给Selenium WebDriver客户端。这样,Selenium WebDriver客户端就可以对Chrome浏览器进行自动化测试了。 

比如我一台电脑上有webdriver,要在另一台电脑上的浏览器运行脚本,怎么办尼

要在另一台电脑上的浏览器运行测试脚本,可以通过远程WebDriver来实现。具体步骤如下:

  1. 在第一台电脑上,启动WebDriver服务器,例如使用ChromeDriver启动Chrome浏览器。

  2. 编写测试脚本,并在脚本中使用WebDriver客户端库连接到WebDriver服务器。

  3. 将测试脚本上传到第二台电脑。

  4. 在第二台电脑上,安装相应的WebDriver客户端库,例如Selenium WebDriver客户端库。

  5. 在测试脚本中指定远程WebDriver服务器的地址和端口,以便与第一台电脑上的WebDriver服务器建立连接。

  6. 运行测试脚本,客户端库将命令发送到远程WebDriver服务器,WebDriver服务器再将命令转发到第一台电脑上的ChromeDriver。

  7. ChromeDriver执行命令,并将执行结果返回到远程WebDriver服务器,最终由客户端库将结果返回到测试脚本。

需要注意的是,为了使用远程WebDriver,第一台电脑和第二台电脑必须在同一局域网中,并且第一台电脑上的WebDriver服务器必须可以被第二台电脑访问到。此外,第一台电脑上的WebDriver服务器和第二台电脑上的测试脚本需要使用相同版本的WebDriver客户端库。

什么叫启动WebDriver 服务器

        启动 WebDriver 服务器指的是在本地或远程计算机上运行一个 WebDriver 服务器进程,以便使用 WebDriver 客户端库连接并控制该服务器来执行自动化测试任务。WebDriver 服务器负责接收来自客户端库的命令,将这些命令转换为浏览器可以执行的操作,然后将执行结果返回给客户端库。常用的 WebDriver 服务器包括 ChromeDriver、GeckoDriver、SafariDriver 等。启动 WebDriver 服务器后,您可以通过编写测试脚本使用 WebDriver 客户端库与服务器进行通信,控制浏览器执行各种自动化测试任务。

什么是selenium server

        Selenium Server 是一个独立的服务器程序,用于启动和管理多个浏览器实例,以便执行分布式 Selenium 自动化测试任务。Selenium Server 是一个 Java 程序,可以在本地或远程计算机上运行。Selenium Server 支持通过 WebDriver 协议或 Selenium Grid 协议与客户端库进行通信,可以通过命令行或配置文件等方式进行配置。

使用 Selenium Server 可以实现在同一台或多台计算机上同时执行多个浏览器实例的自动化测试任务,以提高测试效率和覆盖范围。例如,您可以在多个浏览器上并行执行同一个测试用例,或在不同的浏览器和操作系统上测试您的应用程序。Selenium Server 还提供了一些高级功能,如多浏览器截图、分布式执行、高可用性等,可以满足更复杂的测试需求。

I/local - Selenium standalone server started at http://10.219.94.229:55941/wd/hub为什么这个端口不是4444,而且一直变化尼

        这是因为您正在启动 Selenium Grid,而非单独的 Selenium Standalone 服务器。当您使用 Selenium Grid 时,它将自动为您启动多个 Selenium Standalone 实例,这些实例在不同的端口上监听。这些端口是动态分配的,并且会在每次启动 Selenium Grid 时更改。

在您的情况下,Selenium Grid 已经在 10.219.94.229 上启动,并且它的一个 Selenium Standalone 实例已经在 55941 端口上监听。当您提交 Selenium WebDriver 请求时,请求将被转发到这个 Selenium Standalone 实例,以便执行相应的测试用例。

如果您想要使用固定端口号启动 Selenium Standalone 服务器,您可以使用以下命令:

java -jar selenium-server-standalone.jar -port 4444

这将在 4444 端口上启动 Selenium Standalone 服务器。但是,请注意,这不会启动 Selenium Grid,因此您将无法使用 Selenium Grid 的功能,例如分布式测试。 

什么是selenium standalone server

        Selenium Standalone Server 是一个 Java 服务器,它允许您在本地计算机上运行 Selenium WebDriver 脚本,以便进行自动化测试。它是 Selenium 测试工具中的一个关键组件,可帮助您控制不同的浏览器和操作系统,并在多个浏览器之间执行测试。

        Selenium Standalone Server 提供了一个 HTTP 服务器,用于接收 WebDriver 测试命令,并将它们传递给相应的浏览器实例。它还提供了一个管理控制台,用于监控和管理运行的浏览器实例。

        通过使用 Selenium Standalone Server,您可以轻松地在不同的浏览器和操作系统上运行测试,并自动化测试过程中的重复性任务。例如,您可以使用 Selenium Standalone Server 编写一个自动化测试脚本来测试您的 Web 应用程序在不同浏览器和操作系统下的兼容性。

        要使用 Selenium Standalone Server,您需要下载相应版本的 jar 文件,并在本地计算机上运行它。然后,您可以使用 Selenium WebDriver 客户端库来编写和运行测试脚本,并将它们发送到 Selenium Standalone Server 运行的浏览器实例。

WebDriver 测试命令是通过http请求发送的吗

        是的,WebDriver 测试命令是通过 HTTP 请求发送的。当您编写 Selenium WebDriver 测试脚本时,您可以使用不同的编程语言编写测试脚本,例如 Java、Python、Ruby 或 C# 等。这些编程语言提供了 WebDriver 客户端库,这些库包含可以用于与 Selenium Standalone Server 通信的函数和类。

        当您运行测试脚本时,WebDriver 客户端库将发送 HTTP 请求到 Selenium Standalone Server,并将测试命令打包为 JSON 格式。这些测试命令可以包括启动浏览器、导航到特定的 URL、执行 JavaScript、查找元素或模拟用户输入等操作。Selenium Standalone Server 接收这些测试命令并将其转发给相应的浏览器实例。

        浏览器实例执行测试命令后,将结果返回给 Selenium Standalone Server,然后将结果打包为 JSON 格式发送回客户端。客户端库将解析这些结果,并使用它们来执行后续测试步骤。

        总之,WebDriver 测试命令通过 HTTP 请求发送到 Selenium Standalone Server,并使用 JSON 格式进行传输。这使得 WebDriver 可以与多种编程语言和测试框架集成,并使得编写和运行自动化测试变得更加灵活和可扩展。

 Selenium Standalone Server是通过什么协议将命令发送到浏览器实例的

        Selenium Standalone Server 使用的是 WebDriver 协议(也称为 JSON Wire Protocol)将测试命令发送到浏览器实例。WebDriver 协议是一种基于 HTTP 的协议,它使用 JSON 格式进行数据传输。

        当客户端库发送测试命令时,它会将命令打包为 JSON 格式,并使用 HTTP POST 请求将其发送到 Selenium Standalone Server。请求的 URL 包括 WebDriver 端点和会话 ID。会话 ID 是一个唯一标识符,用于标识正在运行的测试会话。

        Selenium Standalone Server 接收到请求后,将解析 JSON 格式的测试命令,并使用 WebDriver 协议将其转换为浏览器可以理解的命令。然后,它将转换后的命令发送到正在运行的浏览器实例中。

        浏览器实例接收到命令后,将执行相应的操作,并将结果返回给 Selenium Standalone Server。Selenium Standalone Server 将结果打包为 JSON 格式,并使用 HTTP 响应将其发送回客户端库。

        客户端库解析响应后,可以根据响应中的数据进行后续操作,例如获取元素文本、检查页面标题或验证页面状态等。

        综上所述,Selenium Standalone Server 使用 WebDriver 协议将测试命令发送到浏览器实例,并使用 JSON 格式进行数据传输。这种协议的优势在于它可以通过 HTTP 进行通信,并且可以与多种编程语言和测试框架集成。

9、Nodejs异步操作元素用法汇总

使用protractor操作页面元素 (bbsmax.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值