Search code examples
atata

ControlList which contains 2 items returns first items Text element for both items


I have the following code:

public ControlList<PaymentItem, _> PaymentGroup { get; private set; }

[ControlDefinition("div[@id='grant-details']//div", ContainingClass = "payment-details", ComponentTypeName = "Payment Item")]
public class PaymentItem : Control<_>
{
     [FindByXPath("//a[contains(@class, 'test-payment-details-toggle')]")]
     public Link<_> Caret { get; private set; }

     [FindByXPath("//strong[text() = 'Special Instructions:']/parent::p")]
     public Text<_> SpecialInstructions { get; private set; }
}

When I run, the HTML in the source code has 2 div's that match the PaymentItem, the first one of them has the SpecialInstructions Text object with a string value of "None" while the second has some random text, but PaymentGroup[0].SpecialInstructions and PaymentGroup[1].SpecialInstructions both return the value of "None" - it seems to be performing the FindByXPath from the document root instead of the //div with the matching class - what am I doing wrong?


Solution

  • The problem is in incorrect XPath in [FindByXPath("//strong[text() = 'Special Instructions:']/parent::p")]. Either replace // in the beginning with .//, or just remove it (.// will be prepended under the hood by default).

    • // - finds an element from the root of HTML document.
    • .// - finds an element inside the element of parent Atata component.

    Additionally, I would simplify [FindByXPath("//a[contains(@class, 'test-payment-details-toggle')]")] to [FindByClass("test-payment-details-toggle")]. Link<TOwner> refers to <a> in its control definition anyway, so you just need to add a class selector.