diff --git a/src/Bellatrix.Desktop/llm/FindByPrompt.cs b/src/Bellatrix.Desktop/llm/FindByPrompt.cs index 56e0773d..d2e74e64 100644 --- a/src/Bellatrix.Desktop/llm/FindByPrompt.cs +++ b/src/Bellatrix.Desktop/llm/FindByPrompt.cs @@ -163,11 +163,11 @@ private string TryResolveFromPageObjectMemory(string instruction, WindowsDriver< private string ResolveViaPromptFallback(string location, WindowsDriver driver, int maxAttempts = 3) { var viewSnapshotProvider = ServicesCollection.Current.Resolve(); - var summaryJson = viewSnapshotProvider.GetCurrentViewSnapshot(); var failedSelectors = new List(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { + var summaryJson = viewSnapshotProvider.GetCurrentViewSnapshot(); var prompt = SemanticKernelService.Kernel?.InvokeAsync(nameof(LocatorSkill), nameof(LocatorSkill.BuildLocatorPrompt), new() { @@ -229,4 +229,4 @@ private static bool IsElementPresent(WindowsDriver driver, strin } public override string ToString() => $"Prompt = {Value}"; -} +} \ No newline at end of file diff --git a/src/Bellatrix.Mobile/llm/android/FindByPrompt.cs b/src/Bellatrix.Mobile/llm/android/FindByPrompt.cs index 24af6250..be845d01 100644 --- a/src/Bellatrix.Mobile/llm/android/FindByPrompt.cs +++ b/src/Bellatrix.Mobile/llm/android/FindByPrompt.cs @@ -156,11 +156,11 @@ private string TryResolveFromPageObjectMemory(string instruction, object context private string ResolveViaPromptFallback(string location, object context, int maxAttempts = 3) { var snapshotProvider = ServicesCollection.Current.Resolve(); - var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var failedSelectors = new List(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { + var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var prompt = SemanticKernelService.Kernel.InvokeAsync(nameof(AndroidLocatorSkill), nameof(AndroidLocatorSkill.BuildLocatorPrompt), new() { ["viewSummaryJson"] = summaryJson, @@ -224,4 +224,4 @@ private static bool IsElementPresent(object context, string uiautomator) } public override string ToString() => $"Prompt = {Value}"; -} +} \ No newline at end of file diff --git a/src/Bellatrix.Mobile/llm/ios/FindByPrompt.cs b/src/Bellatrix.Mobile/llm/ios/FindByPrompt.cs index b29bc49e..0f5bdc55 100644 --- a/src/Bellatrix.Mobile/llm/ios/FindByPrompt.cs +++ b/src/Bellatrix.Mobile/llm/ios/FindByPrompt.cs @@ -159,11 +159,11 @@ private string TryResolveFromPageObjectMemory(string instruction, object context private string ResolveViaPromptFallback(string location, object context, int maxAttempts = 3) { var snapshotProvider = ServicesCollection.Current.Resolve(); - var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var failedSelectors = new List(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { + var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var prompt = SemanticKernelService.Kernel?.InvokeAsync(nameof(IOSLocatorSkill), nameof(IOSLocatorSkill.BuildLocatorPrompt), new() { @@ -227,4 +227,4 @@ private static bool IsElementPresent(object context, string nspredicate) } public override string ToString() => $"Prompt = {Value}"; -} +} \ No newline at end of file diff --git a/src/Bellatrix.Playwright/components/common/CheckBox.cs b/src/Bellatrix.Playwright/components/common/CheckBox.cs index 7dd3591b..04385f7a 100644 --- a/src/Bellatrix.Playwright/components/common/CheckBox.cs +++ b/src/Bellatrix.Playwright/components/common/CheckBox.cs @@ -35,7 +35,32 @@ public class CheckBox : Component, IComponentDisabled, IComponentChecked, ICompo /// public virtual void Check(LocatorCheckOptions options = default) { - DefaultCheck(Checking, Checked, options); + var tempOptions = options ?? new LocatorCheckOptions(); + tempOptions.Timeout = 1; + + Checking?.Invoke(this, new ComponentActionEventArgs(this)); + this.ValidateIsPresent(); + + try + { + DefaultCheck(null, null, tempOptions); + } + catch + { + // Fallback to JsClick, checkbox may be custom element with hidden input + + if (!IsChecked) + { + var clickOptions = new LocatorClickOptions + { + Force = true, + Timeout = options?.Timeout, + }; + DefaultClick(null, null, clickOptions); + } + } + + Checked?.Invoke(this, new ComponentActionEventArgs(this)); } /// @@ -44,7 +69,33 @@ public virtual void Check(LocatorCheckOptions options = default) /// public virtual void Uncheck(LocatorUncheckOptions options = default) { - DefaultUncheck(Unchecking, Unchecked, options); + var tempOptions = options ?? new LocatorUncheckOptions(); + tempOptions.Timeout = 1; + + Unchecking?.Invoke(this, new ComponentActionEventArgs(this)); + this.ValidateIsPresent(); + + try + { + DefaultUncheck(null, null, tempOptions); + } + catch + { + // Fallback to JsClick, checkbox may be custom element with hidden input + + if (IsChecked) + { + var clickOptions = new LocatorClickOptions + { + Force = true, + Timeout = options?.Timeout, + }; + DefaultClick(null, null, clickOptions); + } + + } + + Unchecked?.Invoke(this, new ComponentActionEventArgs(this)); } public virtual void Hover() diff --git a/src/Bellatrix.Playwright/components/common/RadioButton.cs b/src/Bellatrix.Playwright/components/common/RadioButton.cs index 992c070b..7bc0ba85 100644 --- a/src/Bellatrix.Playwright/components/common/RadioButton.cs +++ b/src/Bellatrix.Playwright/components/common/RadioButton.cs @@ -47,6 +47,28 @@ public virtual void Hover() /// public virtual void Click(LocatorCheckOptions options = default) { - DefaultCheck(Clicking, Clicked, options); + var tempOptions = options ?? new LocatorCheckOptions(); + tempOptions.Timeout = 1; + + Clicking?.Invoke(this, new ComponentActionEventArgs(this)); + this.ValidateIsPresent(); + + try + { + DefaultCheck(null, null, tempOptions); + } + catch + { + // Fallback to JsClick, radio button may be custom element with hidden input + var clickOptions = new LocatorClickOptions + { + Force = true, + Timeout = options?.Timeout, + }; + + DefaultClick(null, null, clickOptions); + } + + Clicked?.Invoke(this, new ComponentActionEventArgs(this)); } } \ No newline at end of file diff --git a/src/Bellatrix.Playwright/components/core/Component.DefaultActions.cs b/src/Bellatrix.Playwright/components/core/Component.DefaultActions.cs index 7af1c2ed..90c93316 100644 --- a/src/Bellatrix.Playwright/components/core/Component.DefaultActions.cs +++ b/src/Bellatrix.Playwright/components/core/Component.DefaultActions.cs @@ -50,7 +50,7 @@ internal void DefaultClick(EventHandler clicking, Even if (options.Force != null && (bool)options.Force) PerformJsClick(); else WrappedElement.Click(options); } - + else WrappedElement.Click(); clicked?.Invoke(this, new ComponentActionEventArgs(this)); @@ -73,7 +73,6 @@ internal void DefaultUncheck(EventHandler unchecking, WrappedElement.Uncheck(options); - @unchecked?.Invoke(this, new ComponentActionEventArgs(this)); } diff --git a/src/Bellatrix.Playwright/components/core/Component.cs b/src/Bellatrix.Playwright/components/core/Component.cs index ce958406..7c3328fb 100644 --- a/src/Bellatrix.Playwright/components/core/Component.cs +++ b/src/Bellatrix.Playwright/components/core/Component.cs @@ -321,7 +321,7 @@ public bool IsPresent { try { - return WrappedElement.ElementHandle(new LocatorElementHandleOptions { Timeout = ConfigurationService.GetSection().TimeoutSettings.InMilliseconds().ElementToExistTimeout }) != null; + return WrappedElement.IsPresent; } catch { diff --git a/src/Bellatrix.Playwright/components/eventhandlers/RadioButtonEventHandlers.cs b/src/Bellatrix.Playwright/components/eventhandlers/RadioButtonEventHandlers.cs index 822882c2..6f786ea6 100644 --- a/src/Bellatrix.Playwright/components/eventhandlers/RadioButtonEventHandlers.cs +++ b/src/Bellatrix.Playwright/components/eventhandlers/RadioButtonEventHandlers.cs @@ -33,4 +33,4 @@ public override void UnsubscribeToAll() RadioButton.Hovering -= HoveringEventHandler; RadioButton.Hovered -= HoveredEventHandler; } -} +} \ No newline at end of file diff --git a/src/Bellatrix.Playwright/llm/FindByPrompt.cs b/src/Bellatrix.Playwright/llm/FindByPrompt.cs index eb758dbf..409bee4b 100644 --- a/src/Bellatrix.Playwright/llm/FindByPrompt.cs +++ b/src/Bellatrix.Playwright/llm/FindByPrompt.cs @@ -17,10 +17,7 @@ using Bellatrix.LLM; using Bellatrix.LLM.Plugins; using Bellatrix.Playwright.LLM.Plugins; -using Bellatrix.Playwright.Locators; -using Microsoft.Identity.Client; using Microsoft.SemanticKernel; -using Pipelines.Sockets.Unofficial.Arenas; using System.Text.RegularExpressions; using System.Threading; @@ -28,7 +25,7 @@ namespace Bellatrix.Playwright.LLM; public class FindByPrompt : FindStrategy { - private bool _tryResolveFromPages = true; + private readonly bool _tryResolveFromPages; /// /// Initializes a new instance of the class with the specified prompt value. /// @@ -58,51 +55,80 @@ private FindStrategy TryResolveLocator(string location, IViewSnapshotProvider sn { if (_tryResolveFromPages) { - // Try from memory - var match = SemanticKernelService.Memory - .SearchAsync(Value, index: "PageObjects", limit: 1) - .Result.Results.FirstOrDefault(); - - if (match != null) + var ragLocator = TryResolveFromPageObjectMemory(Value); + if (ragLocator != null && ragLocator.Resolve(WrappedBrowser.CurrentPage).IsPresent) { - var pageSummary = match.Partitions.FirstOrDefault()?.Text ?? ""; - var mappedPrompt = SemanticKernelService.Kernel - .InvokeAsync(nameof(LocatorMapperSkill), nameof(LocatorMapperSkill.MatchPromptToKnownLocator), new() - { - ["pageSummary"] = pageSummary, - ["instruction"] = Value - }).Result.GetValue(); - - var result = SemanticKernelService.Kernel.InvokePromptAsync(mappedPrompt).Result; - var rawLocator = result?.GetValue()?.Trim(); - var ragLocator = new FindXpathStrategy(rawLocator); - if (ragLocator != null) - { - Logger.LogInformation($"✅ Using RAG-located element '{ragLocator}' For '${Value}'"); - return ragLocator; - } + Logger.LogInformation($"✅ Using RAG-located element '{ragLocator}' For '${Value}'"); + return ragLocator; } } - // Try cache - var cached = LocatorCacheService.TryGetCached(location, Value); - if (!string.IsNullOrEmpty(cached)) + // Step 2: Try local persistent cache + Logger.LogInformation("⚠️ RAG-located element not present. Trying cached selectors..."); + var cached = LocatorCacheService.TryGetCached(WrappedBrowser.CurrentPage.Url, Value); + + var strategy = new FindXpathStrategy(cached); + if (!string.IsNullOrEmpty(cached) && strategy.Resolve(WrappedBrowser.CurrentPage).IsPresent) { - return new FindXpathStrategy(cached); + Logger.LogInformation("✅ Using cached selector."); + return strategy; } - // Remove broken and fall back - LocatorCacheService.Remove(location, Value); + // Step 3: Fall back to AI + prompt regeneration + Logger.LogInformation("⚠️ Cached selector failed or not found. Re-querying AI..."); + LocatorCacheService.Remove(WrappedBrowser.CurrentPage.Url, Value); + return ResolveViaPromptFallback(location, snapshotProvider); } + private static FindXpathStrategy TryResolveFromPageObjectMemory(string instruction) + { + var match = SemanticKernelService.Memory + .SearchAsync(instruction, index: "PageObjects", limit: 1) + .Result.Results.FirstOrDefault(); + + if (match == null) return null; + + var pageSummary = match.Partitions.FirstOrDefault()?.Text ?? string.Empty; + var mappedPrompt = SemanticKernelService.Kernel + .InvokeAsync(nameof(LocatorMapperSkill), nameof(LocatorMapperSkill.MatchPromptToKnownLocator), + new() + { + ["pageSummary"] = pageSummary, + ["instruction"] = instruction + }).Result.GetValue(); + + var locatorResult = SemanticKernelService.Kernel + .InvokePromptAsync(mappedPrompt).Result.GetValue(); + + return ParsePromptLocatorToStrategy(locatorResult); + } + + private static FindXpathStrategy ParsePromptLocatorToStrategy(string promptResult) + { + if (promptResult == "Unknown") + { + return null; + } + + var parts = Regex.Match(promptResult, @"^\s*xpath\s*=\s*(//.+)$", RegexOptions.IgnoreCase); + if (!parts.Success) + { + throw new ArgumentException($"❌ Invalid format. Expected: xpath=//... but received '{promptResult}'"); + } + + var xpath = parts.Groups[1].Value.Trim(); + + return new FindXpathStrategy(xpath); + } + private FindStrategy ResolveViaPromptFallback(string location, IViewSnapshotProvider snapshotProvider, int maxAttempts = 3) { - var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var failedSelectors = new List(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { + var summaryJson = snapshotProvider.GetCurrentViewSnapshot(); var prompt = SemanticKernelService.Kernel .InvokeAsync(nameof(LocatorSkill), nameof(LocatorSkill.BuildLocatorPrompt), new() @@ -113,20 +139,17 @@ private FindStrategy ResolveViaPromptFallback(string location, IViewSnapshotProv }).Result.GetValue(); var result = SemanticKernelService.Kernel.InvokePromptAsync(prompt).Result; - var raw = result?.GetValue()?.Trim(); + var rawSelector = result?.GetValue()?.Trim(); - if (!string.IsNullOrWhiteSpace(raw)) + var strategy = new FindXpathStrategy(rawSelector); + if (!string.IsNullOrWhiteSpace(rawSelector) && strategy.Resolve(WrappedBrowser.CurrentPage).IsPresent) { - var locator = new FindXpathStrategy(raw); - if (locator != null) - { - LocatorCacheService.Update(location, Value, locator.Value); - return locator; - } - - failedSelectors.Add(raw); + LocatorCacheService.Update(location, Value, strategy.Value); + return strategy; } + failedSelectors.Add(rawSelector); + Logger.LogInformation($"[Attempt {attempt}] Selector failed: {rawSelector}"); Thread.Sleep(300); } @@ -134,4 +157,4 @@ private FindStrategy ResolveViaPromptFallback(string location, IViewSnapshotProv } public override string ToString() => $"Prompt = {Value}"; -} +} \ No newline at end of file diff --git a/src/Bellatrix.Playwright/plugins/screenshots/ScreenshotEngine.cs b/src/Bellatrix.Playwright/plugins/screenshots/ScreenshotEngine.cs index e385a2ef..5f8a1de4 100644 --- a/src/Bellatrix.Playwright/plugins/screenshots/ScreenshotEngine.cs +++ b/src/Bellatrix.Playwright/plugins/screenshots/ScreenshotEngine.cs @@ -22,7 +22,14 @@ internal static class ScreenshotEngine public static string TakeScreenshot(ServicesCollection serviceContainer, bool fullPage) { var browser = serviceContainer.Resolve(); - return Convert.ToBase64String(browser.CurrentPage.Screenshot(new PageScreenshotOptions { FullPage = fullPage, Type = ScreenshotType.Png })); + if (browser is not null) + { + return Convert.ToBase64String(browser.CurrentPage.Screenshot(new PageScreenshotOptions { FullPage = fullPage, Type = ScreenshotType.Png })); + } + else + { + return string.Empty; + } } public static string GetEmbeddedResource(string resourceName, Assembly assembly) @@ -44,4 +51,4 @@ private static string FormatResourceName(Assembly assembly, string resourceName) .Replace("\\", ".") .Replace("/", "."); } -} +} \ No newline at end of file diff --git a/src/Bellatrix.Playwright/services/BrowserService.cs b/src/Bellatrix.Playwright/services/BrowserService.cs index 37137423..eda5698f 100644 --- a/src/Bellatrix.Playwright/services/BrowserService.cs +++ b/src/Bellatrix.Playwright/services/BrowserService.cs @@ -138,7 +138,7 @@ public void WaitUntilReady() maxSeconds, sleepTimeMilliseconds: 100); } - + // Faster than sending js and checking for a X state. public void WaitForLoadState(LoadState state = LoadState.Load) { @@ -326,57 +326,55 @@ private void MonkeyPatchXMLHttpRequest() public string GetCurrentViewSnapshot() { var script = @" -(() => { - return JSON.stringify((function deepScan(root) { - const result = []; - const stack = [{ node: root, depth: 0 }]; - - while (stack.length) { - const { node, depth } = stack.pop(); - if (!(node instanceof Element)) continue; - - const style = window.getComputedStyle(node); - const rect = node.getBoundingClientRect(); - - if (style.display !== 'none' && - style.visibility !== 'hidden' && - rect.width > 0 && - rect.height > 0) { - result.push({ - tag: node.tagName.toLowerCase(), - id: node.id, - class: node.className.trim(), - text: node.innerText.trim(), - type: node.getAttribute('type'), - name: node.getAttribute('name'), - placeholder: node.getAttribute('placeholder'), - ariaLabel: node.getAttribute('aria-label'), - role: node.getAttribute('role'), - href: node.getAttribute('href'), - for: node.getAttribute('for'), - value: node.getAttribute('value'), - disabled: node.disabled, - checked: node.type === 'checkbox' ? node.checked : undefined, - selected: node.selected, - shadowDepth: depth, - isInShadowRoot: depth > 0 - }); - } +JSON.stringify((function deepScan(root) { + const result = []; + const stack = [{ node: root, depth: 0 }]; + + while (stack.length) { + const { node, depth } = stack.pop(); + if (!(node instanceof Element)) continue; + + const style = window.getComputedStyle(node); + const rect = node.getBoundingClientRect(); + + if (style.display !== 'none' && + style.visibility !== 'hidden' && + rect.width > 0 && + rect.height > 0) { + result.push({ + tag: node.tagName.toLowerCase(), + id: node.id, + class: node.className.trim(), + text: node.innerText.trim(), + type: node.getAttribute('type'), + name: node.getAttribute('name'), + placeholder: node.getAttribute('placeholder'), + ariaLabel: node.getAttribute('aria-label'), + role: node.getAttribute('role'), + href: node.getAttribute('href'), + for: node.getAttribute('for'), + value: node.getAttribute('value'), + disabled: node.disabled, + checked: node.type === 'checkbox' ? node.checked : undefined, + selected: node.selected, + shadowDepth: depth, + isInShadowRoot: depth > 0 + }); + } - for (const child of node.children) { - stack.push({ node: child, depth }); - } + for (const child of node.children) { + stack.push({ node: child, depth }); + } - if (node.shadowRoot) { - for (const shadowChild of node.shadowRoot.children) { - stack.push({ node: shadowChild, depth: depth + 1 }); - } + if (node.shadowRoot) { + for (const shadowChild of node.shadowRoot.children) { + stack.push({ node: shadowChild, depth: depth + 1 }); } } + } - return result; - })(document.body)); -})() + return result; +})(document.body)); "; var javaScriptService = new JavaScriptService(WrappedBrowser); return javaScriptService.Execute(script); @@ -387,4 +385,4 @@ private string InvokeScript(string scriptToInvoke) JavaScriptService javaScriptService = new JavaScriptService(WrappedBrowser); return javaScriptService.Execute(scriptToInvoke)?.ToString(); } -} +} \ No newline at end of file diff --git a/src/Bellatrix.Playwright/syncplaywright/core/elements/WebElement.cs b/src/Bellatrix.Playwright/syncplaywright/core/elements/WebElement.cs index 525e5166..947565b8 100644 --- a/src/Bellatrix.Playwright/syncplaywright/core/elements/WebElement.cs +++ b/src/Bellatrix.Playwright/syncplaywright/core/elements/WebElement.cs @@ -60,6 +60,21 @@ public ILocator WrappedLocator public BrowserPage Page { get; internal init; } + public bool IsPresent + { + get + { + try + { + return All().Any(); + } + catch + { + return false; + } + } + } + public IReadOnlyList All() { IReadOnlyCollection nativeLocators; diff --git a/src/Bellatrix.Playwright/validators/ValidateControlExtensions.IsPresent.cs b/src/Bellatrix.Playwright/validators/ValidateControlExtensions.IsPresent.cs new file mode 100644 index 00000000..54ef4b98 --- /dev/null +++ b/src/Bellatrix.Playwright/validators/ValidateControlExtensions.IsPresent.cs @@ -0,0 +1,38 @@ +// +// Copyright 2025 Automate The Planet Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Miriam Kyoseva +// https://bellatrix.solutions/ + +using Bellatrix.Playwright.Contracts; +using Bellatrix.Playwright.Events; + +namespace Bellatrix.Playwright; + +public static partial class ValidateControlExtensions +{ + public static void ValidateIsPresent(this T control, int? timeout = null, int? sleepInterval = null) + where T : IComponent + { + WaitUntil(() => control.WrappedElement.IsPresent.Equals(true), $"The control {control.ComponentName} should be present but was NOT.", timeout, sleepInterval); + ValidatedIsPresentEvent?.Invoke(control, new ComponentActionEventArgs(control)); + } + + public static void ValidateIsNotPresent(this T control, int? timeout = null, int? sleepInterval = null) + where T : IComponentVisible, IComponent + { + WaitUntil(() => !control.WrappedElement.IsPresent.Equals(true), $"The control {control.ComponentName} should NOT be present but it was.", timeout, sleepInterval); + ValidatedIsNotPresentEvent?.Invoke(control, new ComponentActionEventArgs(control)); + } + + public static event EventHandler ValidatedIsPresentEvent; + public static event EventHandler ValidatedIsNotPresentEvent; +} \ No newline at end of file diff --git a/src/Bellatrix.Web/llm/FindByPrompt.cs b/src/Bellatrix.Web/llm/FindByPrompt.cs index 79f72b28..9b2dbca5 100644 --- a/src/Bellatrix.Web/llm/FindByPrompt.cs +++ b/src/Bellatrix.Web/llm/FindByPrompt.cs @@ -39,7 +39,7 @@ public class FindByPrompt : FindStrategy /// Initializes a new instance of the class with the specified prompt value. /// /// The natural language prompt used to locate the element. - public FindByPrompt(string value, bool tryResolveFromPages = true) : base(value) + public FindByPrompt(string value, bool tryResolveFromPages = true) : base(value) { _tryResolveFromPages = tryResolveFromPages; } @@ -93,12 +93,12 @@ public override By Convert() private By ResolveViaPromptFallback(IWebDriver driver, string instruction, int maxAttempts = 3) { var viewSnapshotProvider = ServicesCollection.Current.Resolve(); - var summaryJson = viewSnapshotProvider.GetCurrentViewSnapshot(); var failedSelectors = new List(); for (var attempt = 1; attempt <= maxAttempts; attempt++) { - var prompt = SemanticKernelService.Kernel?.InvokeAsync(nameof(LocatorSkill), nameof(LocatorSkill.BuildLocatorPrompt), + var summaryJson = viewSnapshotProvider.GetCurrentViewSnapshot(); + var prompt = SemanticKernelService.Kernel?.InvokeAsync(nameof(LocatorSkill), nameof(LocatorSkill.BuildLocatorPrompt), new() { ["htmlSummary"] = summaryJson, @@ -202,4 +202,4 @@ private static bool IsElementPresent(IWebDriver driver, By by) /// /// A string describing the prompt value. public override string ToString() => $"Prompt = {Value}"; -} +} \ No newline at end of file diff --git a/templates/Bellatrix.Playwright.GettingStarted/40. Prompts Support/PageObjectsTests.cs b/templates/Bellatrix.Playwright.GettingStarted/40. Prompts Support/PageObjectsTests.cs index acf1cb4d..f34769c9 100644 --- a/templates/Bellatrix.Playwright.GettingStarted/40. Prompts Support/PageObjectsTests.cs +++ b/templates/Bellatrix.Playwright.GettingStarted/40. Prompts Support/PageObjectsTests.cs @@ -19,7 +19,7 @@ public void PurchaseRocketWithPageObjects_LLM() //ViewCartButton.ValidateIsVisible(); var product = App.Components.CreateByPrompt("find Add to cart anchor under 'Falcon 9' item"); product.Click(); - + //AssertByPrompt("validate that view cart button is visible"); ValidateByPrompt("validate that view cart button is visible"); @@ -42,7 +42,7 @@ public void PurchaseRocketWithPageObjects_LLM() ValidateByPrompt("validate that the total is 294.67€ euro and the vat is 9.67€ euro and -5.00€ coupon applied, subtotal is 290.00€"); - var deleteLink = App.Components.CreateByPrompt("find 'Saturn V' remove anchor"); + var deleteLink = App.Components.CreateByPrompt("find remove anchor in the 'Saturn V' row"); deleteLink.Click(); var checkoutLink = App.Components.CreateByPrompt("find the checkout link in the main navigation"); diff --git a/templates/Bellatrix.Web.GettingStarted/40. Prompts Support/PageObjectsTests.cs b/templates/Bellatrix.Web.GettingStarted/40. Prompts Support/PageObjectsTests.cs index 85108dd9..80b28be6 100644 --- a/templates/Bellatrix.Web.GettingStarted/40. Prompts Support/PageObjectsTests.cs +++ b/templates/Bellatrix.Web.GettingStarted/40. Prompts Support/PageObjectsTests.cs @@ -21,7 +21,7 @@ public void PurchaseRocketWithPageObjects_LLM() //ViewCartButton.ValidateIsVisible(); var product = App.Components.CreateByPrompt("find Add to cart anchor under 'Falcon 9' item"); product.Click(); - + //AssertByPrompt("validate that view cart button is visible"); ValidateByPrompt("validate that view cart button is visible"); @@ -33,7 +33,7 @@ public void PurchaseRocketWithPageObjects_LLM() var cartPage = App.Create(); cartPage.ApplyCoupon("happybirthday"); - + var product2Quantity = App.Components.CreateByPrompt("find 'Saturn V' quantity number input", false); product2Quantity.SetNumber(2); cartPage.UpdateCart.Click(); @@ -42,7 +42,7 @@ public void PurchaseRocketWithPageObjects_LLM() ValidateByPrompt("validate that the total is 294.67€ euro and the vat is 9.67€ euro and -5.00€ coupon applied, subtotal is 290.00€"); - var deleteLink = App.Components.CreateByPrompt("find 'Saturn V' remove anchor"); + var deleteLink = App.Components.CreateByPrompt("find remove anchor in the 'Saturn V' row"); deleteLink.Click(); var checkoutLink = App.Components.CreateByPrompt("find the checkout link in the main navigation");