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

如何从WebdriverIO中的WebElement继承

  •  6
  • Xotabu4  · 技术社区  · 6 年前

    我在寻找一种继承的方式 WebElement webdriverio 返回,没有猴子补丁和TS类型支持(自动完成是必须的)。有没有办法做这样的事?

    class Checkbox extends WebdriverIOWebElement {
        constructor() {
           super($('div'))
        }
        // overriding base method
        isDisplayed(): boolean {
            // blabla some new logic here
        }
    
        check() {
            if(!this.isChecked()) {
                this.click()
            }
        }
    
        uncheck() {
            if(this.isChecked()) {
                this.click()
            }
        }
    }
    
    0 回复  |  直到 5 年前
        1
  •  3
  •   redhatvicky    5 年前

    举个例子,当我们在HTML中有一个新的标签(我的应用程序)时,我们必须构建一个案例来使用 webdriverIO

    下面是一个基本组件基类,它在其构造函数中接受宿主元素,并将该元素的查询展开到browser对象,这样就可以在许多页面对象(或其他组件对象)中重用它,而不必了解页面本身。

        class Component {
    
          constructor(host) {
            const selectors = [];
            // Crawl back to the browser object, and cache all selectors
            while (host.elementId && host.parent) {
              selectors.push(host.selector);
              host = host.parent;
            }
            selectors.reverse();
            this.selectors_ = selectors;
          }
    
          get host() {
            // Beginning with the browser object, reselect each element
            return this.selectors_.reduce((element, selector) => element.$(selector), browser);
          }
        }
    
        module.exports = Component;
    

    然后我们要做的是,为我们的应用程序登录组件编写一个子类:

    const Component = require('./component');
    
    class Login extends Component {
    
      get usernameInput() {
        return this.host.shadow$('input #username');
      }
    
      get passwordInput() {
        return this.host.shadow$('input[type=password]');
      }
    
      get submitButton() {
        return this.login.shadow$('button[type=submit]');
      }
    
      login(username, password) {
        this.usernameInput.setValue(username);
        this.passwordInput.setValue(password);
        this.submitButton.click();
      }
    }
    
    module.exports = Login;
    

    最后,我们可以在登录页面对象中使用组件对象:

    const Login = require('./components/login');
    
    class LoginPage {
    
      open() {
        browser.url('/login');
      }
    
      get app() {
        return browser.$('my-app');
      }
    
      get loginComponent() {
        // return a new instance of our login component object
        return new Login(this.app.$('app-login'));
      }
    
    }
    

    现在,这个组件对象可以用于测试使用app login web组件的应用程序的任何页面或部分,而不必知道该组件是如何构造的。如果以后决定更改web组件的内部结构,则只需更新组件对象。

    现在我们通过使用阴影Dom支持对复选框组件应用相同的方法:

    public class CheckBox extends Component {
      public CheckBox(element) {
        this.element = element;
      }
      get checkBoxSelector() {
        return this.host.shadow$(element);
      }
      get void toggle() {
        checkBoxSelector().click();
      }
      get void check() {
        if (!isChecked()) {
          toggle();
        }
      }
      get void uncheck() {
        if (isChecked()) {
          toggle();
        }
      }
      get boolean isChecked() {
        return checkBoxSelector().isSelected();
      }
    }
    

    然后我们可以编写一个Check-Box控制器组件,该组件可以使用id获取Check-Box的实例,并验证每个控件都需要什么。

    const CheckBox= require('./components/CheckBox');
    class CheckBoxController{
      open() {
        browser.url('/login');
      }
      get checkboxComponent() {
    
        // Using this we can verify whether the Specific Check Box has been Selected or Not
        let element = browser.$('[id="lpagecheckbox"]');
        return new CheckBox(element);
      }
    }
    

    请记住这不是实际的代码,这只是模板的一部分,可以帮助我们朝着解决问题的方向前进。

    https://webdriver.io/docs/api/element/isSelected.html

    https://webdriver.io/blog/2019/02/22/shadow-dom-support.html

    https://webdriver.io/blog/2019/04/03/react-selectors.html

    https://webdriver.io/docs/pageobjects.html

    此外,如果我们使用seleniumwebdriver,这可以帮助我们实现它

    这里我们有一个接口,它实际上结合了所有 webdriver 接口,然后我们通过继承 Element CheckBox cb = new CheckBox(element);cb.uncheck();

    创建一个包含所有WebDriver接口的接口:

    public interface Element extends WebElement, WrapsElement, Locatable {}
    

    第二步:

    继承元素类的元素实现:

    public class ElementImpl implements Element {
    
        private final WebElement element;
    
        public ElementImpl(final WebElement element) {
            this.element = element;
        }
    
        @Override
        public void click() {
            element.click();
        }
    
        @Override
        public void sendKeys(CharSequence... keysToSend) {
            element.sendKeys(keysToSend);
        }
    
        // And so on, delegates all the way down...
    
    }
    

    第三步: 考虑一下您使用的任何组件,在这种情况下让我们假设复选框

    public class CheckBox extends ElementImpl {
    
        public CheckBox(WebElement element) {
            super(element);
        }
    
        public void toggle() {
            getWrappedElement().click();
        }
    
        public void check() {
            if (!isChecked()) {
                toggle();
            }
        }
    
        public void uncheck() {
            if (isChecked()) {
                toggle();
            }
        }
    
        public boolean isChecked() {
            return getWrappedElement().isSelected();
        }
    }
    

    使用方法:

    CheckBox cb = new CheckBox(element);
    cb.uncheck();
    

    public class Part2ExampleTest {
        private final WebDriver driver;
    
        @FindBy(id = "checkbox")
        CheckBox checkBox;
    
        protected Part2ExampleTest(WebDriver driver) {
            this.driver = driver;
        }
    
        protected static Part2ExampleTest initialize(WebDriver driver) {
            return ElementFactory.initElements(driver, Part2ExampleTest.class);
        }
    
        @Test
        public void simple() {
            WebDriver driver = new FirefoxDriver();
            Part2ExampleTest page = initialize(driver);
    
            PageLoader.get(driver, "forms.html");
    
            Assert.assertFalse(page.checkBox.isChecked());
            page.checkBox.check();
            Assert.assertTrue(page.checkBox.isChecked());
    
            driver.close();
        }
    }
    

    Extend Selenium WebDriver WebElement?

    http://elisarver.com/2012/12/09/wrapping-webelement-1/

    http://elisarver.com/2012/12/10/wrapping-webelement-2

        2
  •  -1
  •   shiva Ram G Athreya    5 年前

    IWebElement 是一个可以在驱动程序类中实现的接口。