断言一个元素是有焦点的

Asserting an element is focused

根据 How do I assert an element is focused? 线程,您可以通过切换到 activeElement() 来检查元素是否获得焦点,并断言这与您期望获得焦点的元素相同:

expect(page.element.getAttribute('id')).toEqual(browser.driver.switchTo().activeElement().getAttribute('id'));

在我的例子中,当前获得焦点的 元素没有 id 属性

除了检查 id 我应该怎么做?

奖金问题:另外,正如您从我尝试解决它所看到的那样,看起来我不能 expect/assert 将元素(或网络元素)作为一个完整的对象。为什么?


我试过:

expect(page.element).toEqual(browser.driver.switchTo().activeElement());

但是失败并出现一个我什至无法理解的错误 - 有一个巨大的回溯(在控制台中滚动大约需要 10 分钟),但内部没有用户友好的错误。

我也尝试过使用 getWebElement():

expect(page.element.getWebElement()).toEqual(browser.driver.switchTo().activeElement());

但这导致了以下错误:

Error: expect called with WebElement argument, expected a Promise. Did you mean to use .getText()?

使用最新的量角器开发版本。

您需要想出一种方法来告诉 Protractor/webdriver 如何在页面上找到您的元素。 Protractor 使用 JavaScript 来查找元素,因此可以使用任何可用于检查 DOM 的工具。 Protractor 和 webdriver 将这些 API 包装在各种 by 风格中:

http://angular.github.io/protractor/#/api?view=ProtractorBy

除了基本风味外,量角器还添加了 Angular 感知风味(因此您可以通过 Angular 绑定等进行搜索)。

如果您的元素没有任何显着特征,那么可能值得添加一些东西以使其更易于测试。或者,(虽然这经常不受欢迎,因为它太脆弱了),您可以使用 xpath。参见 https://github.com/angular/protractor/blob/master/docs/locators.md

奇怪的是它只期待一个 promise 而不能处理 webdriver 元素...我有和你一样的巨大堆栈跟踪。

无论如何,你会接受这种解决方案吗:发送一个 "dumb" 承诺,并附上一个很好的评论来证明你为什么必须这样做。我承认,它更像是一种解决方法,而不是一种语义解决方案。

expect(page.element.getInnerHtml())
  .toEqual(browser.driver.switchTo().activeElement().getInnerHtml());

它对我有用 ;)

编辑:奖励答案

您不能使用 WebElement 调用 expect 的原因来自 Webdriver Control Flow Principle (I'm sure you already know about) and this line in jasminewd,由 Protractor 开发和使用的 jasmine 到 Webdriver 的适配器 ;)

您可以简单地检查元素的文本(或其他任何内容):

var currentElement = browser.switchTo().activeElement();
expect(currentElement.getText()).toEqual(page.element.getText());

在我的回答中,我假设 activeElempageElem 都是量角器元素查找器,并且指向同一个 Web 元素。

先回答你为什么

expect(activeElem).toEqual(pageElem);

进入无限循环,这是因为量角器修补了 jasmine 的 expect 以在断言之前解决承诺,因此 expect(activeElem.getText()).toEqual('text'); 之类的事情无需执行

activeElem.getText().then(function(text) {
  expect(text).toEqual('text');
})

你可能会说,为什么不只 resolve 一次 promise 呢?但是还有嵌套的承诺。

所以现在您可能认为这是一个问题,但事实并非如此,因为您永远不会在实际用例中比较两个 elementFinder。 Jasmine 的 toEqual 进行引用检查,而不是深度比较,因此 expect(activeElem).toEqual(pageElem) 与简单的引用比较相同:(activeElem === pageElem).toToTruthy(),这样做真的没有意义。 (注意 element(by.css('html')) === element(by.css('html')) 是错误的,因为它不是同一个引用。)

所以,要回答这个线程的真正问题:如何查看两个 elementFinder 是否具有相同的底层 webelements:

expect(activeElem.getId()).toEqual(pageElem.getId());

对于未来的读者,我创建了一个 custom matcher 来断言元素是否为 active/focused:

beforeEach(function() {
    jasmine.addMatchers({
        toBeActive: function() {
            return {
                compare: function(elm) {
                    return {
                        pass: elm.getId().then(function (activeElementID) {
                            return browser.driver.switchTo().activeElement().getId().then(function (currentElementID) {
                                return jasmine.matchersUtil.equals(currentElementID, activeElementID);
                            });
                        })
                    };
                }
            };
        }
    });
});

用法:

expect(element(by.css("#myid")).toBeActive();

如何使用 CSS 选择器和 :focus

expect(element.all(by.css('#myid:focus')).count()).toBe(1);

我用量角器解决了这个问题: ElementFinder.prototype.equals

const activeElement = await browser.driver.switchTo().activeElement();
const potentialyFocusedElement = await component.$('your-locator');
const isFocused = await potentialyFocusedElement.equals(activeElement);

我不确定 equals 到底是如何工作的,如果它进行深度比较,或者它以某种方式比较实例。但它有效。

请注意,您不能调用 activeElement.equals(...),因为它不是 ElementFinder,而是 WebElement