module Dsl
open System
open System.Threading.Tasks
open Microsoft.Playwright
[<AbstractClass; Sealed>]
type Locators() =
static member GetByLabel (text: string) (page: IPage) = page.GetByLabel(text)
static member GetByRole role options (page: IPage) = page.GetByRole(role, options)
static member Button options = Locators.GetByRole AriaRole.Button options
static member Button text = Locators.GetByRole AriaRole.Button (PageGetByRoleOptions(Name = text))
static member Button(text, ?exact, ?disabled) = Locators.GetByRole AriaRole.Button (PageGetByRoleOptions(Name = text, Exact = defaultArg exact false, Disabled = Option.toNullable disabled))
static member Heading text = Locators.GetByRole AriaRole.Heading (PageGetByRoleOptions(Name = text))
static member Heading(text, ?exact, ?level) = Locators.GetByRole AriaRole.Heading (PageGetByRoleOptions(Name = text, Exact = Option.toNullable exact, Level = Option.toNullable level))
static member Heading options = Locators.GetByRole AriaRole.Heading options
static member Link text = Locators.GetByRole AriaRole.Link (PageGetByRoleOptions(Name = text))
static member Link(text, ?exact) = Locators.GetByRole AriaRole.Link (PageGetByRoleOptions(Name = text, Exact = Option.toNullable exact))
static member Label text = Locators.GetByLabel text
static member Label(text: string, ?exact) = fun (page: IPage) -> page.GetByLabel(text, PageGetByLabelOptions(Exact = Option.toNullable exact))
static member Label(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByLabel(pattern)
static member Locator (selector: string) (page: IPage) = page.Locator(selector)
static member ByText(text: string, options) = fun (page: IPage) -> page.GetByText(text, options)
static member ByText(text: string, ?exact) = fun (page: IPage) -> page.GetByText(text, PageGetByTextOptions(Exact = (defaultArg exact false)))
static member ByText(text: Text.RegularExpressions.Regex, options) = fun (page: IPage) -> page.GetByText(text, options)
static member ByText(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByText(pattern)
static member ByPlaceholder(text: string) = fun (page: IPage) -> page.GetByPlaceholder(text)
static member ByPlaceholder(text: string, ?exact) = fun (page: IPage) -> page.GetByPlaceholder(text, PageGetByPlaceholderOptions(Exact = Option.toNullable exact))
static member ByPlaceholder(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByPlaceholder(pattern)
static member ByTestId(text: string) = fun (page: IPage) -> page.GetByTestId(text)
static member ByTestId(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByTestId(pattern)
static member ByAltText(text: string) = fun (page: IPage) -> page.GetByAltText(text)
static member ByAltText(text: string, ?exact) = fun (page: IPage) -> page.GetByAltText(text, PageGetByAltTextOptions(Exact = Option.toNullable exact))
static member ByAltText(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByAltText(pattern)
static member ByTitle(text: string) = fun (page: IPage) -> page.GetByTitle(text)
static member ByTitle(text: string, ?exact) = fun (page: IPage) -> page.GetByTitle(text, PageGetByTitleOptions(Exact = Option.toNullable exact))
static member ByTitle(pattern: Text.RegularExpressions.Regex) = fun (page: IPage) -> page.GetByTitle(pattern)
static member Textbox text = Locators.GetByRole AriaRole.Textbox (PageGetByRoleOptions(Name = text))
static member Textbox(text, ?exact) = Locators.GetByRole AriaRole.Textbox (PageGetByRoleOptions(Name = text, Exact = Option.toNullable exact))
static member Checkbox text = Locators.GetByRole AriaRole.Checkbox (PageGetByRoleOptions(Name = text))
static member Checkbox(text, ?exact, ?isChecked) = Locators.GetByRole AriaRole.Checkbox (PageGetByRoleOptions(Name = text, Exact = Option.toNullable exact, Checked = Option.toNullable isChecked))
static member Combobox text = Locators.GetByRole AriaRole.Combobox (PageGetByRoleOptions(Name = text))
static member Combobox(text, ?expanded) = Locators.GetByRole AriaRole.Combobox (PageGetByRoleOptions(Name = text, Expanded = Option.toNullable expanded))
static member Tab text = Locators.GetByRole AriaRole.Tab (PageGetByRoleOptions(Name = text))
static member Tab(text, ?selected) = Locators.GetByRole AriaRole.Tab (PageGetByRoleOptions(Name = text, Selected = Option.toNullable selected))
static member MenuItem text = Locators.GetByRole AriaRole.Menuitem (PageGetByRoleOptions(Name = text))
let expect f (locator: ILocator) = f (Assertions.Expect(locator))
type Locator = IPage -> ILocator
type Transition<'t> = Locator * (unit -> 't)
let inline (||>) (parent: Locator) f page = f (parent page)
type State<'pom> = Task<'pom>
type UiTestBuilder<'initialPlr>(page: IPage, plr: 'initialPlr) =
let withPage (state: State<'pom>) f =
task {
let! pom = state
let! _ = f page
return pom
}
let withPageTask (state: State<'pom>) (f: IPage -> Task) =
task {
let! pom = state
do! f page
return pom
}
let act (state: State<'pom>) (locator: 'pom -> Locator) (f: ILocator -> Task) =
task {
let! pom = state
let locator = locator pom page
do! f locator
return pom
}
let applyWithoutTransition (state: State<'pom>) (locator: 'pom -> Transition<_>) (f: ILocator -> Task) =
task {
let! pom = state
let locator, _ = locator pom
do! f (locator page)
return pom
}
let apply (state: State<'pom>) (locator: 'pom -> Transition<_>) (f: ILocator -> Task) =
task {
let! pom = state
let locator, next = locator pom
do! f (locator page)
return next ()
}
member _.Yield(()) : State<'initialPlr> =
Task.FromResult plr
[<CustomOperation("fill", MaintainsVariableSpace = true)>]
member _.Fill(state: State<'page>, locator, text: string, ?timeout: float32, ?force: bool) =
act state locator _.FillAsync(text, LocatorFillOptions(Timeout = Option.toNullable timeout, Force = Option.toNullable force))
[<CustomOperation("write", MaintainsVariableSpace = true)>]
member _.Write(state, locator, text: string, ?delay: float32) =
act state locator _.PressSequentiallyAsync(text, LocatorPressSequentiallyOptions(Delay = Option.toNullable delay))
[<CustomOperation("page", MaintainsVariableSpace = true)>]
member _.Page(state, f) = withPage state f
[<CustomOperation("page", MaintainsVariableSpace = true)>]
member _.Page(state, f) = withPageTask state f
[<CustomOperation("expectVisible", MaintainsVariableSpace = true)>]
member _.ExpectVisible(state, getLocator, ?timeout: float32) =
act state getLocator (expect _.ToBeVisibleAsync(LocatorAssertionsToBeVisibleOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectVisible", MaintainsVariableSpace = true)>]
member _.ExpectVisible(state, getLocator, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToBeVisibleAsync(LocatorAssertionsToBeVisibleOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectVisible", MaintainsVariableSpace = true)>]
member _.ExpectVisible(state, getLocator, arg) =
act
state
(fun plr -> getLocator plr arg)
(expect _.ToBeVisibleAsync())
[<CustomOperation("click")>]
member _.Click(state, locator) = act state locator _.ClickAsync()
[<CustomOperation("click")>]
member _.Click(state, locator, options: LocatorClickOptions) = act state locator _.ClickAsync(options)
[<CustomOperation("click")>]
member _.Click(state, getTransition) = apply state getTransition _.ClickAsync()
[<CustomOperation("click")>]
member _.Click(state, getTransition, options: LocatorClickOptions) = apply state getTransition _.ClickAsync(options)
[<CustomOperation("click")>]
member _.Click(state, getTransition, arg, options: LocatorClickOptions) =
act
state
(fun plr -> getTransition plr arg )
_.ClickAsync(options)
[<CustomOperation("click")>]
member _.Click(state, getTransition, arg) =
apply
state
(fun plr -> getTransition plr arg )
_.ClickAsync()
[<CustomOperation("printf")>]
member _.PrintF(state, msg, arg) =
task {
let! state = state
printfn msg arg
return state
}
[<CustomOperation("print")>]
member _.Print(state, msg) =
task {
let! state = state
printfn "%s" msg
return state
}
[<CustomOperation("wait_s")>]
member _.WaitS(state, delay: int) =
task {
let! state = state
do! Task.Delay(1000 * delay)
return state
}
[<CustomOperation("wait_ms")>]
member _.WaitMs(state, delay: int) =
task {
let! state = state
do! Task.Delay(delay)
return state
}
[<CustomOperation("takeAriaSnapshot")>]
member _.TakeAriaSnapshot state =
task {
let! state = state
let! snapshot = page.AriaSnapshotAsync()
printfn "%s" snapshot
return state
}
[<CustomOperation("takeAriaSnapshot")>]
member _.TakeAriaSnapshot(state, locator) =
act
state
locator
(fun x ->
task {
let! snapshot = x.AriaSnapshotAsync()
printfn "%s" snapshot
}
)
[<CustomOperation("takeAriaSnapshot")>]
member _.TakeAriaSnapshot(state, locator) =
applyWithoutTransition
state
locator
(fun x ->
task {
let! snapshot = x.AriaSnapshotAsync()
printfn "%s" snapshot
return ()
}
)
[<CustomOperation("hover", MaintainsVariableSpace = true)>]
member _.Hover(state, locator, ?force: bool) = act state locator _.HoverAsync(LocatorHoverOptions(Force = Option.toNullable force))
[<CustomOperation("hover", MaintainsVariableSpace = true)>]
member _.Hover(state, getTransition, ?force: bool) = apply state getTransition _.HoverAsync(LocatorHoverOptions(Force = Option.toNullable force))
[<CustomOperation("dblClick")>]
member _.DblClick(state, locator) = act state locator _.DblClickAsync()
[<CustomOperation("dblClick")>]
member _.DblClick(state, getTransition) = apply state getTransition _.DblClickAsync()
[<CustomOperation("check", MaintainsVariableSpace = true)>]
member _.Check(state, locator) = act state locator _.CheckAsync()
[<CustomOperation("uncheck", MaintainsVariableSpace = true)>]
member _.Uncheck(state, locator) = act state locator _.UncheckAsync()
[<CustomOperation("press", MaintainsVariableSpace = true)>]
member _.Press(state, locator, key: string) = act state locator _.PressAsync(key)
[<CustomOperation("selectOption", MaintainsVariableSpace = true)>]
member _.SelectOption(state, locator, value: string) = act state locator _.SelectOptionAsync(value)
[<CustomOperation("focus", MaintainsVariableSpace = true)>]
member _.Focus(state, locator) = act state locator _.FocusAsync()
[<CustomOperation("clear", MaintainsVariableSpace = true)>]
member _.Clear(state, locator) = act state locator _.ClearAsync()
[<CustomOperation("waitFor", MaintainsVariableSpace = true)>]
member _.WaitFor(state, locator, ?timeout: float32) =
act state locator _.WaitForAsync(LocatorWaitForOptions(Timeout = Option.toNullable timeout))
[<CustomOperation("waitFor", MaintainsVariableSpace = true)>]
member _.WaitFor(state, locator, waitState: WaitForSelectorState) =
act state locator _.WaitForAsync(LocatorWaitForOptions(State = waitState))
[<CustomOperation("waitFor", MaintainsVariableSpace = true)>]
member _.WaitFor(state, getTransition, ?timeout: float32) =
applyWithoutTransition state getTransition _.WaitForAsync(LocatorWaitForOptions(Timeout = Option.toNullable timeout))
[<CustomOperation("expectHidden", MaintainsVariableSpace = true)>]
member _.ExpectHidden(state, getLocator, ?timeout: float32) =
act state getLocator (expect _.ToBeHiddenAsync(LocatorAssertionsToBeHiddenOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectHidden", MaintainsVariableSpace = true)>]
member _.ExpectHidden(state, getLocator, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToBeHiddenAsync(LocatorAssertionsToBeHiddenOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectEnabled", MaintainsVariableSpace = true)>]
member _.ExpectEnabled(state, getLocator, ?timeout: float32) =
act state getLocator (expect _.ToBeEnabledAsync(LocatorAssertionsToBeEnabledOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectEnabled", MaintainsVariableSpace = true)>]
member _.ExpectEnabled(state, getLocator, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToBeEnabledAsync(LocatorAssertionsToBeEnabledOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectDisabled", MaintainsVariableSpace = true)>]
member _.ExpectDisabled(state, getLocator, ?timeout: float32) =
act state getLocator (expect _.ToBeDisabledAsync(LocatorAssertionsToBeDisabledOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectDisabled", MaintainsVariableSpace = true)>]
member _.ExpectDisabled(state, getLocator, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToBeDisabledAsync(LocatorAssertionsToBeDisabledOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectChecked", MaintainsVariableSpace = true)>]
member _.ExpectChecked(state, getLocator, ?timeout: float32) =
act state getLocator (expect _.ToBeCheckedAsync(LocatorAssertionsToBeCheckedOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectChecked", MaintainsVariableSpace = true)>]
member _.ExpectChecked(state, getLocator, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToBeCheckedAsync(LocatorAssertionsToBeCheckedOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("expectText", MaintainsVariableSpace = true)>]
member _.ExpectText(state, getLocator, text: string, ?ignoreCase: bool, ?timeout: float32) =
act state getLocator (expect _.ToHaveTextAsync(text, LocatorAssertionsToHaveTextOptions(IgnoreCase = Option.toNullable ignoreCase, Timeout = Option.toNullable timeout)))
[<CustomOperation("expectText", MaintainsVariableSpace = true)>]
member _.ExpectText(state, getLocator, text: string, ?ignoreCase: bool, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToHaveTextAsync(text, LocatorAssertionsToHaveTextOptions(IgnoreCase = Option.toNullable ignoreCase, Timeout = Option.toNullable timeout)))
[<CustomOperation("expectContainsText", MaintainsVariableSpace = true)>]
member _.ExpectContainsText(state, getLocator, text: string, ?ignoreCase: bool, ?timeout: float32) =
act state getLocator (expect _.ToContainTextAsync(text, LocatorAssertionsToContainTextOptions(IgnoreCase = Option.toNullable ignoreCase, Timeout = Option.toNullable timeout)))
[<CustomOperation("expectContainsText", MaintainsVariableSpace = true)>]
member _.ExpectContainsText(state, getLocator, text: string, ?ignoreCase: bool, ?timeout: float32) =
applyWithoutTransition state getLocator (expect _.ToContainTextAsync(text, LocatorAssertionsToContainTextOptions(IgnoreCase = Option.toNullable ignoreCase, Timeout = Option.toNullable timeout)))
[<CustomOperation("expectCount", MaintainsVariableSpace = true)>]
member _.ExpectCount(state, getLocator, count: int, ?timeout: float32) =
act state getLocator (expect _.ToHaveCountAsync(count, LocatorAssertionsToHaveCountOptions(Timeout = Option.toNullable timeout)))
[<CustomOperation("reload", MaintainsVariableSpace = true)>]
member _.Reload(state) = withPage state _.ReloadAsync()
[<CustomOperation("goBack", MaintainsVariableSpace = true)>]
member _.GoBack(state) = withPage state _.GoBackAsync()
[<CustomOperation("goForward", MaintainsVariableSpace = true)>]
member _.GoForward(state) = withPage state _.GoForwardAsync()
[<CustomOperation("waitForURL", MaintainsVariableSpace = true)>]
member _.WaitForURL(state, url: string) = withPageTask state _.WaitForURLAsync(url)
[<CustomOperation("screenshot", MaintainsVariableSpace = true)>]
member _.Screenshot(state, path: string) =
withPage state _.ScreenshotAsync(PageScreenshotOptions(Path = path))
[<CustomOperation("withPage")>]
member _.WithPagh(state,f) =
withPage state f
let pageTest page = UiTestBuilder page