using Microsoft.Playwright;
namespace Tests.E2e.PageObjectModels;
public class DocsPom(IPage page) {
// -------------------------------------------------
// Root
// -------------------------------------------------
public ILocator Viewer
=> page.GetByTestId("docs-viewer");
public ILocator HomeLink
=> page.GetByTestId("docs-home-link");
public ILocator SearchInput
=> page.GetByTestId("docs-search-input");
// -------------------------------------------------
// Index
// -------------------------------------------------
///
/// Every sidebar entry. Matched on the test-id prefix so the assertions
/// survive docs being added to or removed from docs-index.json.
///
public ILocator IndexLinks
=> page.Locator("[data-testid^='docs-index-link-']");
///
/// A single sidebar entry, addressed by its source file name
/// (e.g. "overview.md" -> docs-index-link-overview-md).
///
public ILocator IndexLink(string docFileName)
=> page.GetByTestId($"docs-index-link-{Sanitize(docFileName)}");
private static string Sanitize(string value)
=> value.Replace(" ", "-")
.Replace("/", "-")
.Replace("\\", "-")
.Replace(".", "-");
// -------------------------------------------------
// High-Level Actions
// -------------------------------------------------
public async Task AssertLoadedAsync() {
await Assertions.Expect(Viewer).ToBeVisibleAsync();
await Assertions.Expect(SearchInput).ToBeVisibleAsync();
}
public async Task OpenDocAsync(string docFileName) {
await IndexLink(docFileName).ClickAsync();
await page.WaitForURLAsync($"**/docs/{docFileName.Replace(".md", "")}");
}
///
/// The search box is a plain Blazor @bind, which updates on the change
/// event rather than on input. Playwright's FillAsync only raises input,
/// so the value must be committed with an explicit blur — elsewhere in
/// the app a Generate button happens to do that as a side effect.
///
public async Task SearchAsync(string filter) {
await SearchInput.FillAsync(filter);
await SearchInput.BlurAsync();
}
public async Task AssertContentContainsAsync(string text)
=> await Assertions.Expect(Viewer).ToContainTextAsync(text);
///
/// Guards issue #304: when the Blazor Server host cannot read the docs
/// assets it renders the "document not found" placeholder rather than
/// failing outright, so a passing page load is not on its own proof the
/// content resolved.
///
public async Task AssertContentResolvedAsync() {
await Assertions.Expect(Viewer).Not.ToContainTextAsync("document not found");
await Assertions.Expect(Viewer).Not.ToContainTextAsync("loading documentation…");
}
public async Task AssertIndexResolvedAsync() {
await Assertions.Expect(Viewer).Not.ToContainTextAsync("docs index not found");
await Assertions.Expect(IndexLinks.First).ToBeVisibleAsync();
}
}