Search code examples
c#playwrightplaywright-dotnet

Playwright C# - finding an element in an iframe and out of an iframe


I'm new-ish to C# and SO, please let me know if I can improve anything.

We're following the page object model and I have a page that I need to use inside and out of an iframe.

It looks like this at the moment:

public class MyPage {
    protected IPage Page;

    public MyPage (IPage page) {
        Page = page;
    }

    public ILocator MyButton => Page.Locator("#myButton");
}

public class MyPageIframe {
    protected IFrameLocator MyIframe;

    public MyPageIframe (IPage page) {
        MyIframe = page.FrameLocator("#myIframe");
    }

    public MyButton => MyIframe.Locator("#myButton");
}

The locators for both are exactly the same, except the context the Locator() method is called on. Is there a way to make these the same class, with one MyButton that works with or without the iframe?

In my head, the magic solution would be something like this:

public class MyPage {
    // where someType can be either IPage or IFrameLocator
    protected someType context;

    public MyPage(IPage page, IFrameLocator locator) {
        // do something to set context?
    }

    public MyButton => context.Locator("#myButton");
}

Solution

  • The first solution that came to my mind for your problem is this:

    using var playwright = await Playwright.CreateAsync();
    await using var browser = await playwright.Chromium.LaunchAsync();
    var page = await browser.NewPageAsync();
    
    var home = new HomePage(page);
    ILocator myButton = home.MyButton;
    ILocator myOtherButton = home.MyOtherButton;
    
    public abstract class BasePage
    {
        protected BasePage(IPage page)
        {
            Page = page;
        }
    
        protected IPage Page { get; }
    
        public virtual ILocator Locate(string frameLocator, string locator) => Page.FrameLocator(frameLocator).Locator(locator);
    
        public virtual ILocator Locate(string locator) => Page.Locator(locator);
    }
    
    public class HomePage : BasePage
    {
        public HomePage(IPage page)
            : base(page)
        {
        }
    
        public ILocator MyButton => Locate("#myButton");
        public ILocator MyOtherButton => Locate("#myIframe", "#myOtherButton");
    }