diff --git a/src/canopy/canopy.fs b/src/canopy/canopy.fs index 99318bdb..aaf1b455 100644 --- a/src/canopy/canopy.fs +++ b/src/canopy/canopy.fs @@ -192,7 +192,7 @@ let waitFor2 message (f : unit -> bool) = let waitFor = waitFor2 "Condition not met in given amount of time. If you want to increase the time, put compareTimeout <- 10.0 anywhere before a test to increase the timeout" //find related -let rec private findElements cssSelector (searchContext : ISearchContext) : IWebElement list = +let rec private findElements cssSelector (searchContext : ISearchContext) counter : IWebElement list = searchedFor <- (cssSelector, browser.Url) :: searchedFor let findInIFrame () = let iframes = findByCss "iframe" searchContext.FindElements @@ -204,16 +204,17 @@ let rec private findElements cssSelector (searchContext : ISearchContext) : IWeb iframes |> List.iter (fun frame -> browser.SwitchTo().Frame(frame) |> ignore let root = browser.FindElement(By.CssSelector("html")) - webElements := findElements cssSelector root - ) + webElements := findElements cssSelector root counter + ) !webElements - try - let results = - configuredFinders cssSelector searchContext.FindElements + let results = + configuredFinders cssSelector (tryToOptimizeFindersForPerformance && counter <= 3) searchContext.FindElements |> Seq.filter(fun list -> not(list.IsEmpty)) if Seq.isEmpty results then - findInIFrame() + if skipTryingToFindElementsInIFramesForPerformance && counter = 1 then + [] + else findInIFrame() else results |> Seq.head with | ex -> [] @@ -224,12 +225,14 @@ let private findByFunction cssSelector timeout waitFunc searchContext reliable = try if reliable then let elements = ref [] + let counter = ref 0 wait.Until(fun _ -> - elements := waitFunc cssSelector searchContext + counter := !counter + 1 + elements := waitFunc cssSelector searchContext !counter not <| List.isEmpty !elements) |> ignore !elements else - wait.Until(fun _ -> waitFunc cssSelector searchContext) + wait.Until(fun _ -> waitFunc cssSelector searchContext 0) with | :? WebDriverTimeoutException -> suggestOtherSelectors cssSelector @@ -769,6 +772,6 @@ let coverage (url : 'a) = let addFinder finder = let currentFinders = configuredFinders - configuredFinders <- (fun cssSelector f -> - currentFinders cssSelector f + configuredFinders <- (fun cssSelector optimize f -> + currentFinders cssSelector optimize f |> Seq.append (seq { yield finder cssSelector f })) \ No newline at end of file diff --git a/src/canopy/configuration.fs b/src/canopy/configuration.fs index bad57482..3393b493 100644 --- a/src/canopy/configuration.fs +++ b/src/canopy/configuration.fs @@ -19,4 +19,6 @@ let mutable disableSuggestOtherSelectors = false let mutable autoPinBrowserRightOnLaunch = true let mutable throwIfMoreThanOneElement = false let mutable configuredFinders = finders.defaultFinders -let mutable writeToSelectWithOptionValue = true \ No newline at end of file +let mutable writeToSelectWithOptionValue = true +let mutable tryToOptimizeFindersForPerformance = true +let mutable skipTryingToFindElementsInIFramesForPerformance = true \ No newline at end of file diff --git a/src/canopy/finders.fs b/src/canopy/finders.fs index 05303447..ecf86a38 100644 --- a/src/canopy/finders.fs +++ b/src/canopy/finders.fs @@ -53,15 +53,32 @@ let findByValue value f = findByCss (sprintf "*[value='%s']" value) f |> List.ofSeq with | _ -> [] +let mutable htmlElements = [ "html"; "body"; "ul"; "li"; "a "; "p "; "div"; "span"; "table"; "tr"; "td"; "thead"; "tbody"; "label"; "input"; "button"; "select"; "option"; "textarea" ] //using a(space) instead of a because I dont want to match any word starting with a + +let mutable selectorIsProbablyXpath = fun (selector : string) -> selector.StartsWith("/") || selector.Contains("id(") || selector.Contains("text()") +let mutable selectorIsProbablyJQuery = fun (selector : string) -> not <| selectorIsProbablyXpath selector && selector.Contains(":") //:eq :contains etc +let mutable selectorIsProbablyCSS = fun (selector : string) -> not <| selectorIsProbablyJQuery selector && (selector.StartsWith("#") || selector.StartsWith(".") || htmlElements |> List.exists (fun html -> selector.StartsWith(html))) +let mutable selectorIsProbablyValue = fun (selector : string) -> not <| selectorIsProbablyCSS selector +let mutable selectorIsProbablyLabel = fun (selector : string) -> not <| selectorIsProbablyCSS selector +let mutable selectorIsProbablyText = fun (selector : string) -> not <| selectorIsProbablyCSS selector + //you can use this as an example to how to extend canopy by creating your own set of finders, tweaking the current collection, or adding/removing let mutable defaultFinders = - (fun cssSelector f -> + (fun cssSelector optimize f -> seq { - yield findByCss cssSelector f - yield findByValue cssSelector f - yield findByXpath cssSelector f - yield findByLabel cssSelector f - yield findByText cssSelector f - yield findByJQuery cssSelector f + if optimize then + if selectorIsProbablyCSS cssSelector then yield findByCss cssSelector f + if selectorIsProbablyValue cssSelector then yield findByValue cssSelector f + if selectorIsProbablyXpath cssSelector then yield findByXpath cssSelector f + if selectorIsProbablyLabel cssSelector then yield findByLabel cssSelector f + if selectorIsProbablyText cssSelector then yield findByText cssSelector f + if selectorIsProbablyJQuery cssSelector then yield findByJQuery cssSelector f + else + yield findByCss cssSelector f + yield findByValue cssSelector f + yield findByXpath cssSelector f + yield findByLabel cssSelector f + yield findByText cssSelector f + yield findByJQuery cssSelector f } ) \ No newline at end of file