Fallenreaper Fallenreaper - 3 years ago 269
Dart Question

testing a component with complex angular components nested inside using PageObjects

Our Application has components which consume components with consume components of varying complexity. So i just want the input on the page, to validate when an object is set that the text is correct. The issue is that it is one of these subcomponents.

My colleague told me that there is 2 ways to do this, The first is to use Page Objects, and Chaining annotation to find it on my page, and then find the next id etc until my input is found. It requires me to look through another teams' Component Markup to narrow it down to the input i want to leverage. I dont believe I should have to go into another component definition, or a definition of a definition to get the appropriate chain to get this arbitrary input. It starts to create issues where if a lateral team creates changes unbeknownst to me, my PO will be broken.

The other option my friend asked was to use

to find the component. This would be as simple as:

fixture.query((el)=> el.attribute["id"] == "description",
expect(comp.value, value);

Using Query looks at the markup but then will automatically componentize it as the appropriate SubComponent. In this case, comp.value is the value stored in the HTML. So, if i did something like:

fixture.update((MainComponent comp) {
comp.myinput.value = new Foo();

Then I am setting and getting this programmatically, so i am a bit unsure if it properly would reflect what is on the screen.

Whats the best course of action? It seems PO would be better, but im not sure if there is a way around having to deep query for input boxes outside of the component i am testing.


Answer Source

I don't think I have a definitive answer for you but I can tell you how we do it at Google. For pretty much any component we provide the page object alongside the component. This is twofold it is for testing that widget, and also so we can have this as a shareable resource for other tests.

For leaf widgets the page objects are a little less fleshed out and are really just there for the local test. For components that are shared heavily the page object is a bit more flushed out for reusability. Without this much of the API for the widget (html, css, etc) we would need to consider public and changes to them would be very hard (person responsible for making the public breaking change needs to fix all associated code.) With it we can have a contract to only support the page object API and html structure changes are not considered breaking changes. At times we have even gone so far as to have two page objects for a widget. One for the local test, and one to share. Sometimes the API you want to expose for a local test is much more than you want people to use themselves.

We can then compose these page objects into higher level page objects that represent the widget. Good page objects support a higher level of abstraction for that widget. For example a calendar widget would let you go to the next/previous month, get the current selected date, etc. rather than directly exposing the buttons/inputs that accomplish those actions.

We plan to expose these page objects for angular_components eventually, but we are currently working on how to expose these. Our internal package structure is different than what we have externally. We have many packages per individual widget (page_objects, examples, widget itself) and we need to reconcile this externally before we expose them.

Here is an example:

import 'package:pageloader/objects.dart';
import 'material_button_po.dart';

/// Webdriver page object for `material-yes-no-buttons` component.
class MaterialYesNoButtonsPO {
  MaterialButtonPO yesButton;

  MaterialButtonPO noButton;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download