GPAL - Generally Positive Automation Library v1.0
GPAL The Fluent Automation LIbrary
Loading...
Searching...
No Matches
Selector.cs
1// =============================================================================
2// GPAL - Generally Positive Automation Library
3// Copyright © 2026 Software Decisions, Inc. All rights reserved.
4//
5// This file is part of GPAL.
6// Licensed under the Business Source License 1.1
7//
8// Primary development, architecture, and vision by Michael B. Vederman,
9// CEO of Software Decisions, Inc., Texas.
10//
11// Internal development maintained privately.
12// Public releases appear on GitHub: https://github.com/SoftwareDecisionsInc/GPAL.
13//
14// See LICENSE for full terms, including Additional Use Grant.
15// =============================================================================
16
17using System;
18using System.Collections.Generic;
19using System.Drawing;
20using System.Linq;
21using System.Text;
22using System.Threading.Tasks;
23using OpenQA.Selenium;
24using static GenerallyPositive.Enums;
27using System.Windows.Automation;
29using System.Reflection;
31
32/*
33 var searchSelector = GPAL.Selector
34 .WithCSS(string) // class
35 .WithXpath(string) // id / name
36 .WithText(string) // value
37 .WithImage(string) // image path or image ptr?
38 .WithOffset(coor) // for clicking x,y coord
39 .EvaluationOrder(enum) // order to try finding object
40*/
41namespace GenerallyPositive
42{
43 internal class SmallSelectorNode
44 {
45 public InteractionType InteractionType { get; internal set; }
46 public int OffsetX { get; internal set; }
47 public int OffsetY { get; internal set; }
48 public int DeltaX { get; internal set; }
49 public int DeltaY { get; internal set; }
50 }
55 public class Selector : IAllowSelectorSettings
56 {
57 // deep copy cannot have property passed as ref
58 internal SelectorSettings selectorSettings = null;
59 public SelectorSettings SelectorSettings
60 {
61 get
62 {
63 return selectorSettings;
64 }
65 internal set
66 {
67 selectorSettings = value;
68 }
69 }
70
71 public SelectorType SelectorType
72 {
73 get
74 {
75 return SelectorSettings.SelectorType;
76 }
77
78 set
79 {
80 selectorSettings.SelectorType = value;
81 }
82 }
83 private Application.Application MyApplication { get; set; } = null;
84
85 public Selector ToGPALObject()
86 {
87 return this;
88 }
89
99 public delegate CallIfStatus webMatchingFunction(List<IGPALElement> foundElements, out List<IGPALElement> matchedElements, out bool matchedAll, Selector selector, bool ExactMatch = true);
100
110 public delegate CallIfStatus appMatchingFunction(List<GPALAutomationElement> foundElements, out List<GPALAutomationElement> matchedElements, out bool matchedAll, Selector selector, bool ExactMatch = true);
111
112
113 internal Selector(Browser.Browser browser, Selector selector)
114 {
115 SelectorSettings = new SelectorSettings();
116
117 Browser = browser;
118 selectorSettings = ObjectCopier.DeepCopyObject(selector.SelectorSettings, selectorSettings, DeepCopy.FieldsAndProperties);
119 if (true == string.IsNullOrEmpty(selector.Name))
120 Name = $"Selector{browser.CurrentUOW.WithSelectorList.Count}";
121 else
122 Name = selector.Name; // shoulda been copied?
123
125 }
126 internal Selector(Browser.Browser browser)
127 {
128 Browser = browser;
130 Name = $"Selector{browser.CurrentUOW.WithSelectorList.Count}";
131 }
132
133 internal Selector(Application.Application application, Selector selector)
134 {
135 SelectorSettings = new SelectorSettings();
136
137 MyApplication = application;
138 selectorSettings = ObjectCopier.DeepCopyObject(selector.SelectorSettings, selectorSettings, DeepCopy.FieldsAndProperties);
139 if (true == string.IsNullOrEmpty(selector.Name))
140 Name = $"Selector{application.CurrentUOW.WithSelectorList.Count}";
141 else
142 Name = selector.Name; // shoulda been copied?
143
145 }
146 internal Selector(Application.Application application)
147 {
148 MyApplication = application;
149 SelectorSettings = new SelectorSettings();
150 Name = $"Selector{application.CurrentUOW.WithSelectorList.Count}";
151 }
152 internal Selector()
153 {
154 SelectorSettings = new SelectorSettings();
155 }
156 internal bool AnyMatchCriteria()
157 {
158 return 0 < MatchCriteria.Count;
159 }
160
161 #region <Fluent Settings>
169 {
170 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = css, SelectorPathType = SelectorPathType.Css };
171 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
172 return this;
173 }
174
181 {
182 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = xPath, SelectorPathType = SelectorPathType.Xpath };
183 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
184 return this;
185 }
186
193 {
194 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = text, SelectorPathType = SelectorPathType.Text };
195 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
196 return this;
197 }
198
205 {
206 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = value, SelectorPathType = SelectorPathType.Value };
207 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
208 return this;
209 }
210
217 {
218 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = name, SelectorPathType = SelectorPathType.Name };
219 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
220 return this;
221 }
222
228 public IAllowSelectorSettings WithClassName(string className)
229 {
230 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = className, SelectorPathType = SelectorPathType.ClassName };
231 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
232 return this;
233 }
234
240 public IAllowSelectorSettings WithAutomationID(string automationID)
241 {
242 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = automationID, SelectorPathType = SelectorPathType.AutomationID };
243 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
244 return this;
245 }
246
252 public IAllowSelectorSettings WithPlaceholder(string placeholder)
253 {
254 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = placeholder, SelectorPathType = SelectorPathType.PlaceHolder };
255 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
256 return this;
257 }
258
265 public IAllowSelectorSettings WithImage(string base64String)
266 {
267 try
268 {
269 Image image = ImageHelper.Base64ToImage(base64String);
270 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPathType = SelectorPathType.Image, Image = image };
271 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
272 } catch
273 {
274 // try passing the string as a filename, it's not base64
275 return WithImage((GPALFile)base64String);
276 }
277 return this;
278 }
279
287 {
288 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPathType = SelectorPathType.Image, Image = image };
289 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
290 return this;
291 }
292
298 [SingleUse(Description = "Search inside the element this selector already found rather than the whole page")]
299 public IAllowSelectorSettings WithSearchForSelector(bool searchForElement)
300 {
301 SelectorSettings.SearchForSelector = searchForElement;
302 return this;
303 }
304
310 [SingleUse(Description = "A name for this selector, used as the column header when its data is saved and in the events it publishes")]
312 {
313 SelectorSettings.Name = name;
314 return this;
315 }
316
321 [SingleUse(Description = "How far to drag horizontally from where the element was grabbed, in pixels")]
323 {
324 SelectorSettings.DeltaX = deltaX;
325 return this;
326 }
327
332 [SingleUse(Description = "How far to drag vertically from where the element was grabbed, in pixels")]
334 {
335 SelectorSettings.DeltaY = deltaY;
336 return this;
337 }
338
343 [SingleUse(Description = "Where to click inside the element, in pixels right of its left edge. Unset clicks the centre")]
345 {
346 SelectorSettings.OffsetX = offsetX;
347 return this;
348 }
349
354 [SingleUse(Description = "Where to click inside the element, in pixels down from its top edge. Unset clicks the centre")]
356 {
357 SelectorSettings.OffsetY = offsetY;
358 return this;
359 }
360
365 [SingleUse(Description = "Move the pointer to the element along a curve rather than jumping straight there")]
367 {
368 SelectorSettings.SimulateMouse = moveWithArc;
369 SelectorSettings.InteractionType = InteractionType.Hardware;
370 SelectorSettings.RequestedInteractionType = InteractionType.Hardware;
371 return this;
372 }
373 [SingleUse(Description = "Read this attribute from the element instead of its text when data is retrieved")]
374 public IAllowSelectorSettings UseAttribute(string attributeName)
375 {
376 SelectorSettings.AttributeName = attributeName;
377 return this;
378 }
384 public IAllowSelectorSettings MatchFunction(Selector.appMatchingFunction matchingFunction)
385 {
386 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Custom, AppMatchingFunction = matchingFunction };
387 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
388 return this;
389 }
390
395 public IAllowSelectorSettings MatchFunction(Selector.webMatchingFunction matchingFunction)
396 {
397 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Custom, WebMatchingFunction = matchingFunction };
398 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
399 return this;
400 }
401
406 public IAllowSelectorSettings MatchAttribute(string attributeToMatch)
407 {
408 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Attribute, StringToMatch = attributeToMatch };
409 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
410 return this;
411 }
412
417 public IAllowSelectorSettings MatchAttributeRegex(string attributeToMatch)
418 {
419 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Attribute, StringToMatch = attributeToMatch };
420 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
421 return this;
422 }
423
428 public IAllowSelectorSettings MatchHRef(string hrefToMatch) // image path or actual image?
429 {
430 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Href, StringToMatch = hrefToMatch };
431 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
432 return this;
433 }
434
439 public IAllowSelectorSettings MatchHRefRegex(string hrefToMatch) // image path or actual image?
440 {
441 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Href, StringToMatch = hrefToMatch };
442 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
443 return this;
444 }
445
450 public IAllowSelectorSettings MatchPlaceholder(string placeholderToMatch) // image path or actual image?
451 {
452 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Placeholder, StringToMatch = placeholderToMatch };
453 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
454 return this;
455 }
456
461 public IAllowSelectorSettings MatchPlaceholderRegex(string placeholderToMatch) // image path or actual image?
462 {
463 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Placeholder, StringToMatch = placeholderToMatch };
464 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
465 return this;
466 }
467
472 public IAllowSelectorSettings MatchSrc(string srcToMatch)
473 {
474 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Src, StringToMatch = srcToMatch };
475 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
476 return this;
477 }
478
483 public IAllowSelectorSettings MatchSrcRegex(string srcToMatch)
484 {
485 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Src, StringToMatch = srcToMatch };
486 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
487 return this;
488 }
489
494 public IAllowSelectorSettings MatchText(string textToMatch)
495 {
496 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Text, StringToMatch = textToMatch };
497 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
498 return this;
499 }
500
505 public IAllowSelectorSettings MatchTextRegex(string textToMatch)
506 {
507 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Text, StringToMatch = textToMatch };
508 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
509 return this;
510 }
511
516 public IAllowSelectorSettings MatchValue(string valueToMatch)
517 {
518 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Value, StringToMatch = valueToMatch };
519 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
520 return this;
521 }
522
527 public IAllowSelectorSettings MatchValueRegex(string valueToMatch)
528 {
529 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Regex | MatchType.Value, StringToMatch = valueToMatch };
530 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
531 return this;
532 }
533
536 public void Remove()
537 {
538 DeleteMe = true;
539 }
540
546 //public IAllowSelectorSettings WithOCR(string textToFind)
547 //{
548 // throw new NotImplementedException();
549 //}
555 public IAllowSelectorSettings WithStopOnNotFound(bool stopOnNotFound)
556 {
557 SelectorSettings.StopOnNotFound = stopOnNotFound;
558 return this;
559 }
560 public IAllowSelectorSettings CallIfFound(CallIfDelegate callIfFound)
561 {
562 SelectorSettings.CallIfFound.Add(callIfFound);
563 return this;
564 }
565 public IAllowSelectorSettings CallIfNotFound(CallIfDelegate callIfNotFound)
566 {
567 SelectorSettings.CallIfNotFound.Add(callIfNotFound);
568 return this;
569 }
570
579 {
580 foreach (string filename in imageToFindPath.Filenames)
581 {
582 SelectorSettings.SelectorPathEntry selectorPathEntry = new SelectorSettings.SelectorPathEntry { SelectorPath = filename, SelectorPathType = SelectorPathType.Image };
583 SelectorSettings.SelectorPaths.Add(selectorPathEntry);
584 }
585 return this;
586 }
587
595 public IAllowSelectorSettings WithHRef(string HRefFullOrPartial)
596 {
597 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Href, StringToMatch = HRefFullOrPartial };
598 matchCriteriaEntry.ExactMatch = false;
599 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
600 return this;
601 }
602 #endregion <Fluent Settings>
603
604 #region <Getter/Setters>
605
606 // TECHNIQUES of dealing with Selector
612 {
613 get
614 {
615 SelectorSettings.InteractionType = InteractionType.Hardware;
616 SelectorSettings.RequestedInteractionType = InteractionType.Hardware;
617 return this;
618 }
619 }
620
625 {
626 get
627 {
628 SelectorSettings.InteractionType = InteractionType.JavaScript;
629 SelectorSettings.RequestedInteractionType = InteractionType.JavaScript;
630 return this;
631 }
632 }
633
638 {
639 get
640 {
641 SelectorSettings.InteractionType = InteractionType.Selenium;
642 SelectorSettings.RequestedInteractionType = InteractionType.Selenium;
643 return this;
644 }
645 }
646
651 {
652 get
653 {
654 return SelectorSettings.ElementsFoundAndMatchedCount;
655 }
656 internal set
657 {
658 SelectorSettings.ElementsFoundAndMatchedCount = value;
659 }
660 }
661 internal CallIfStatus AppCallIfFoundHandled
662 {
663 get
664 {
665 return SelectorSettings.AppCallIfFoundHandled;
666 }
667 set
668 {
669 SelectorSettings.AppCallIfFoundHandled = value;
670 }
671 }
672 internal CallIfStatus AppCallIfNotFoundHandled
673 {
674 get
675 {
676 return SelectorSettings.AppCallIfNotFoundHandled;
677 }
678 set
679 {
680 SelectorSettings.AppCallIfNotFoundHandled = value;
681 }
682 }
683 internal CallIfStatus CallIfFoundHandled
684 {
685 get
686 {
687 return SelectorSettings.CallIfFoundHandled;
688 }
689 set
690 {
691 SelectorSettings.CallIfFoundHandled = value;
692 }
693 }
694 internal CallIfStatus CallIfNotFoundHandled
695 {
696 get
697 {
698 return SelectorSettings.CallIfNotFoundHandled;
699 }
700 set
701 {
702 SelectorSettings.CallIfNotFoundHandled = value;
703 }
704 }
705 internal Application.Application Application
706 {
707 get
708 {
709 return MyApplication;
710 }
711 set
712 {
713 MyApplication = value;
714 }
715 }
716 internal List<Application.Application.CallIfDelegate> AppCallIfFound
717 {
718 get
719 {
720 return SelectorSettings.AppCallIfFound;
721 }
722 }
723 internal List<Application.Application.CallIfDelegate> AppCallIfNotFound
724 {
725 get
726 {
727 return SelectorSettings.AppCallIfNotFound;
728 }
729 }
730 internal string AttributeName
731 {
732 get
733 {
734 return SelectorSettings.AttributeName;
735 }
736 }
743 {
744 get
745 {
746 return SelectorSettings.InteractionType;
747 }
748 internal set
749 {
750 SelectorSettings.InteractionType = value;
751 }
752 }
753
758 {
759 get;
760 internal set;
761 }
762
765 public string SelectorPath
766 {
767 get
768 {
769 return SelectorSettings.SelectorPaths[0].SelectorPath;
770 }
771 }
772
776 public List<SelectorSettings.SelectorPathEntry> SelectorPaths
777 {
778 get
779 {
780 return SelectorSettings.SelectorPaths;
781 }
782 }
783 internal List<SelectorSettings.MatchCriteriaEntry> MatchCriteria
784 {
785 get
786 {
787 return SelectorSettings.MatchCriteria;
788 }
789 }
795 {
796 get
797 {
798 return SelectorSettings.SearchForSelector;
799 }
800 }
801
806 public int OffsetX
807 {
808 get
809 {
810 return SelectorSettings.OffsetX;
811 }
812 internal set
813 {
814 SelectorSettings.OffsetX = value;
815 }
816 }
817
822 public int OffsetY
823 {
824 get
825 {
826 return SelectorSettings.OffsetY;
827 }
828 internal set
829 {
830 SelectorSettings.OffsetY = value;
831 }
832 }
833
837 public int DeltaX
838 {
839 get
840 {
841 return SelectorSettings.DeltaX;
842 }
843 internal set
844 {
845 SelectorSettings.DeltaX = value;
846 }
847 }
848
852 public int DeltaY
853 {
854 get
855 {
856 return SelectorSettings.DeltaY;
857 }
858 internal set
859 {
860 SelectorSettings.DeltaY = value;
861 }
862 }
863
869 public string Name
870 {
871 get
872 {
873 return SelectorSettings.Name;
874 }
875
876 internal set
877 {
878 SelectorSettings.Name = value;
879 }
880 }
881
884 internal bool DeleteMe
885 {
886 get
887 {
888 return SelectorSettings.DeleteMe;
889 }
890 set
891 {
892 SelectorSettings.DeleteMe = value;
893 }
894 }
900 internal List<Browser.Browser.CallIfDelegate> RemovedMethods
901 {
902 get
903 {
904 return SelectorSettings.RemovedMethods;
905 }
906 set
907 {
908 SelectorSettings.RemovedMethods = value;
909 }
910 }
917 internal InteractionType? RequestedInteractionType
918 {
919 get
920 {
921 return SelectorSettings.RequestedInteractionType;
922 }
923 set
924 {
925 SelectorSettings.RequestedInteractionType = value;
926 }
927 }
932 public bool SimulateMouse
933 {
934 get
935 {
936 return SelectorSettings.SimulateMouse;
937 }
938 }
939
943 public bool StopOnNotFound
944 {
945 get
946 {
947 return SelectorSettings.StopOnNotFound;
948 }
949 }
950
951 public List<GPALElement> WebSelectorFoundResults
952 {
953 get
954 {
955 foreach (var selectorPathEntry in SelectorPaths)
956 if (null != selectorPathEntry.WebSelectorFoundResults)
957 return selectorPathEntry.WebSelectorFoundResults;
958
959 return null;
960 }
961 set
962 {
963 foreach (var selectorPathEntry in SelectorPaths)
964 selectorPathEntry.WebSelectorFoundResults = value;
965 }
966 }
967 public List<GPALElement> WebSelectorMatchedResults
968 {
969 get
970 {
971 foreach (var selectorPathEntry in SelectorPaths)
972 if (null != selectorPathEntry.WebSelectorMatchedResults)
973 return selectorPathEntry.WebSelectorMatchedResults;
974
975 return null;
976 }
977 set
978 {
979 foreach (var selectorPathEntry in SelectorPaths)
980 selectorPathEntry.WebSelectorMatchedResults = value;
981 }
982 }
983
984 #endregion <Getter/Setters>
985
986 #region Implicit String Conversion, so wherever Selector parameter is expected, a string can be used directly
987 // implicit ToString
988 public static implicit operator string(Selector sel) => sel.Name;
989
990 private static int implicitCount = 0;
991 // ────────────────────────────────────────────────
992 // 1. Implicit conversion from string to Selector
993 // ────────────────────────────────────────────────
994 public static implicit operator Selector(string selectorString)
995 {
996 var sel = new Selector();
997
998 if (string.IsNullOrWhiteSpace(selectorString))
999 {
1000 // Fail forward: warn + continue with empty/invalid-but-safe selector
1001 GPAL.PublishSimpleEvent(
1002 GPALEventType.WARNING,
1003 "Invalid selector path treating as empty selector (no paths added).",
1004 selectorString,
1005 GPALObjectType.Selector
1006 );
1007
1008 // Optional: give it a name so it's obvious in logs/reports
1009 sel.WithSelectorName($"EmptySelector{implicitCount++}");
1010 }
1011 else
1012 {
1013 bool looksLikeXPath = IsLikelyXPath(selectorString);
1014
1015 if (looksLikeXPath)
1016 {
1017 // XPath first - more specific / less false positives in ambiguous cases
1018 sel.WithXPath(selectorString);
1019 sel.WithCSS(selectorString); // still try as CSS as fallback
1020 }
1021 else
1022 {
1023 // CSS first - most people intuitively write CSS selectors
1024 sel.WithCSS(selectorString);
1025 sel.WithXPath(selectorString); // still try as XPath fallback
1026 }
1027
1028 // give it a recognizable debug name
1029 sel.WithSelectorName($"Implicit{implicitCount++}.{(looksLikeXPath ? "XPath" : "CSS")}.{Shorten(selectorString, 10)}");
1030 }
1031
1032 GPAL.PublishSimpleEvent(GPALEventType.DEBUG, $"Implicit selector [{sel.Name}] created for [{selectorString}]");
1033
1034 // emit warning once.
1035 if (1 == implicitCount)
1036 GPAL.PublishSimpleEvent(GPALEventType.DEBUG, $"Implicit selector conversions lack equality, even if paths match. Create instance using GPAL.Selector for reuse.", sel, GPALObjectType.Selector);
1037
1038 return sel;
1039 }
1040
1041 // Very short helper for debug/readable names
1042 private static string Shorten(string s, int maxLen)
1043 {
1044 if (s.Length <= maxLen) return s;
1045 return s.Substring(0, maxLen - 3) + "...";
1046 }
1047
1048 // ────────────────────────────────────────────────
1049 // 2. The helper that guesses CSS vs XPath
1050 // ────────────────────────────────────────────────
1054 public static bool IsLikelyXPath(string s)
1055 {
1056 if (string.IsNullOrWhiteSpace(s)) return false;
1057 s = s.Trim();
1058
1059 // Strong XPath starters (absolute, descendant-or-self, id function)
1060 if (s.StartsWith("/") || s.StartsWith(".//") || s.StartsWith("//") || s.StartsWith("id("))
1061 return true;
1062
1063 // Classic browser-copied XPath: html/body/div[NN]/... pattern
1064 if (char.IsLetter(s[0]) && s.Contains("/") && s.Contains("["))
1065 return true;
1066
1067 // XPath-specific constructs that almost never appear in CSS
1068 if (s.Contains("::") ||
1069 s.Contains("/following") ||
1070 s.Contains("/preceding") ||
1071 s.Contains("/ancestor") ||
1072 s.Contains("/parent") ||
1073 s.Contains("/child") ||
1074 s.Contains("position()") ||
1075 s.Contains("last()") ||
1076 s.Contains("normalize-space") ||
1077 s.Contains("contains(text()") ||
1078 (s.Contains("@") && s.Contains("=") && !s.Contains("["))) // @attr="value" without [
1079 {
1080 return true;
1081 }
1082
1083 // Lone @attr (very strong XPath signal)
1084 if (s.Contains("@") && !s.Contains("["))
1085 return true;
1086
1087 // Very strong CSS indicators -> definitely treat as CSS, not XPath
1088 if (s.StartsWith("#") ||
1089 s.StartsWith(".") ||
1090 s.Contains(">") ||
1091 s.Contains("+") ||
1092 s.Contains("~") ||
1093 s.Contains(":not(") ||
1094 s.Contains(":nth-child") ||
1095 s.Contains(":nth-of-type"))
1096 {
1097 return false;
1098 }
1099
1100 // Contains [ but no other strong CSS markers -> lean toward XPath
1101 if (s.Contains("[") && !s.Contains(":") && !s.Contains("#") && !s.Contains("."))
1102 return true;
1103
1104 // Final fallback - assume CSS unless strong XPath evidence
1105 return false;
1106 }
1107 #endregion
1108
1109 public IAllowSelectorSettings ContainsAttribute(string attributeToMatch)
1110 {
1111 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Attribute, StringToMatch = attributeToMatch };
1112 matchCriteriaEntry.ExactMatch = false;
1113 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1114 return this;
1115 }
1116
1117 public IAllowSelectorSettings ContainsHRef(string hrefToMatch)
1118 {
1119 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Href, StringToMatch = hrefToMatch };
1120 matchCriteriaEntry.ExactMatch = false;
1121 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1122 return this;
1123 }
1124
1125 public IAllowSelectorSettings ContainsPlaceholder(string placeholderToMatch)
1126 {
1127 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Placeholder, StringToMatch = placeholderToMatch };
1128 matchCriteriaEntry.ExactMatch = false;
1129 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1130 return this;
1131 }
1132
1133 public IAllowSelectorSettings ContainsSrc(string srcToMatch)
1134 {
1135 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Src, StringToMatch = srcToMatch };
1136 matchCriteriaEntry.ExactMatch = false;
1137 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1138 return this;
1139 }
1140
1141 public IAllowSelectorSettings ContainsText(string textToMatch)
1142 {
1143 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Text, StringToMatch = textToMatch };
1144 matchCriteriaEntry.ExactMatch = false;
1145 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1146 return this;
1147 }
1148
1149 public IAllowSelectorSettings ContainsValue(string valueToMatch)
1150 {
1151 SelectorSettings.MatchCriteriaEntry matchCriteriaEntry = new SelectorSettings.MatchCriteriaEntry { MatchType = MatchType.Value, StringToMatch = valueToMatch };
1152 matchCriteriaEntry.ExactMatch = false;
1153 SelectorSettings.MatchCriteria.Add(matchCriteriaEntry);
1154 return this;
1155 }
1156 }
1157}
1158
Application object that contains the fluent methods to create your Application workflow....
Browser object that contains the fluent methods to create your Browser workflow. Instatiated using G...
Definition Browser.cs:68
GPAL File object instantied with GPAL.File Used to load tokens into a GPALGrid [rows/columns].
Definition GPALFile.cs:36
Provides comprehensive image capture, conversion, and matching capabilities for automation scenarios....
static Image Base64ToImage(string base64String)
Converts a Base64 string (with or without data URI prefix) to a System.Drawing.Image.
GPAL Selector used to locate Application and Browser elements. Instantiated with GPAL....
Definition Selector.cs:56
IAllowSelectorSettings WithSelectorName(string name)
A common name for this selector. Used in Information and Exception channel messages.
Definition Selector.cs:311
string SelectorPath
Returns the first defined selector path string.
Definition Selector.cs:766
int DeltaX
Drag-and-drop deltaX to move from the elemenet.X + OffsetX.
Definition Selector.cs:838
IAllowSelectorSettings MatchText(string textToMatch)
Found elements must match the text supplied in order to interact with them.
Definition Selector.cs:494
IAllowSelectorSettings WithJavaScript
Interact with this element using javascript injected into the page.
Definition Selector.cs:625
IAllowSelectorSettings MatchValueRegex(string valueToMatch)
Found elements must match the value regular expression supplied in order to interact with them.
Definition Selector.cs:527
IAllowSelectorSettings MatchTextRegex(string textToMatch)
Found elements must match the text regular expression supplied in order to interact with them.
Definition Selector.cs:505
IAllowSelectorSettings MatchAttribute(string attributeToMatch)
Found elements must have attribute supplied in order to interact with them.
Definition Selector.cs:406
Browser.Browser Browser
Browser associated with this selector.
Definition Selector.cs:758
IAllowSelectorSettings WithDeltaY(int deltaY)
Define the y offset from the Top Left corner to perform clicks.
Definition Selector.cs:333
IAllowSelectorSettings WithImage(Image image)
Define an image to match on-screen. The top left corner is used as the start of the element....
Definition Selector.cs:286
bool StopOnNotFound
Stop the workflow if no elements are found for this selector.
Definition Selector.cs:944
void Remove()
Remove this selector from the current Unit of Work.
Definition Selector.cs:536
IAllowSelectorSettings WithPlaceholder(string placeholder)
Define the placeholder used to find elements, matched in full against the placeholder attribute....
Definition Selector.cs:252
IAllowSelectorSettings WithText(string text)
Define Text used to find elements by text attribute. Browser only.
Definition Selector.cs:192
IAllowSelectorSettings WithDeltaX(int deltaX)
Define the x offset from the Top Left corner to perform clicks.
Definition Selector.cs:322
IAllowSelectorSettings MatchPlaceholder(string placeholderToMatch)
Found elements must match the placeholder supplied in order to interact with them.
Definition Selector.cs:450
bool SearchForSelector
Search for elements on the page.
Definition Selector.cs:795
IAllowSelectorSettings MatchFunction(Selector.appMatchingFunction matchingFunction)
Your custom application element matching function to examine found elements and return only those you...
Definition Selector.cs:384
IAllowSelectorSettings MatchSrc(string srcToMatch)
Found elements must match the src supplied in order to interact with them.
Definition Selector.cs:472
int DeltaY
Drag-and-drop deltaY to move from the elemenet.Y + OffsetY.
Definition Selector.cs:853
int OffsetY
Y offset fromm the top left corner to interact with the element, image match included....
Definition Selector.cs:823
IAllowSelectorSettings MatchFunction(Selector.webMatchingFunction matchingFunction)
Your custom web element matching function to examine found elements and return only those you 'match'...
Definition Selector.cs:395
IAllowSelectorSettings WithClassName(string className)
Define Name used to find elements by name attribute. Application only.
Definition Selector.cs:228
IAllowSelectorSettings MatchAttributeRegex(string attributeToMatch)
Found elements must have the attribute specified by regular expression in order to interact with them...
Definition Selector.cs:417
int ElementsFoundAndMatchedCount
Count of elements found for this selector (after match).
Definition Selector.cs:651
InteractionType InteractionType
Defined method to interact with this element. NOTE: This can be overridden in the workflow.
Definition Selector.cs:743
IAllowSelectorSettings WithSelenium
Interact with this element using Selenium [default].
Definition Selector.cs:638
IAllowSelectorSettings WithValue(string value)
Define Value used to find elements by value attribute. Browser only.
Definition Selector.cs:204
IAllowSelectorSettings WithName(string name)
Define Name used to find elements by name attribute. Application only.
Definition Selector.cs:216
IAllowSelectorSettings WithXPath(string xPath)
Define XPath used to find elements Both.
Definition Selector.cs:180
IAllowSelectorSettings WithImage(GPALFile imageToFindPath)
Define an image to match on-screen. The top left corner is used as the start of the element....
Definition Selector.cs:578
IAllowSelectorSettings MatchHRefRegex(string hrefToMatch)
Found elements must match the HRef regular expression supplied in order to interact with them.
Definition Selector.cs:439
IAllowSelectorSettings MatchValue(string valueToMatch)
Found elements must match the value supplied in order to interact with them.
Definition Selector.cs:516
delegate CallIfStatus webMatchingFunction(List< IGPALElement > foundElements, out List< IGPALElement > matchedElements, out bool matchedAll, Selector selector, bool ExactMatch=true)
Custom matching function, must return all matched elements and an indicator as to whether all element...
static bool IsLikelyXPath(string s)
Rudimentary but reasonably effective guess: is this string more likely an XPath than a CSS selector?
Definition Selector.cs:1054
IAllowSelectorSettings WithSimulateMouse(bool moveWithArc)
Simulate a human moving the mouse when interacting with this element. Implies hardware input.
Definition Selector.cs:366
IAllowSelectorSettings WithAutomationID(string automationID)
Define Name used to find elements by name attribute. Application only.
Definition Selector.cs:240
IAllowSelectorSettings WithOffsetX(int offsetX)
Define the x offset from the Top Left corner to perform clicks.
Definition Selector.cs:344
delegate CallIfStatus appMatchingFunction(List< GPALAutomationElement > foundElements, out List< GPALAutomationElement > matchedElements, out bool matchedAll, Selector selector, bool ExactMatch=true)
Custom matching function, must return all matched elements and an indicator as to whether all element...
IAllowSelectorSettings MatchPlaceholderRegex(string placeholderToMatch)
Found elements must match the placeholder regular expression supplied in order to interact with them.
Definition Selector.cs:461
IAllowSelectorSettings WithImage(string base64String)
Define an image to match on-screen. The top left corner is used as the start of the element....
Definition Selector.cs:265
List< SelectorSettings.SelectorPathEntry > SelectorPaths
The selector paths defined to locate elements.
Definition Selector.cs:777
IAllowSelectorSettings MatchHRef(string hrefToMatch)
Found elements must match the HRef supplied in order to interact with them.
Definition Selector.cs:428
IAllowSelectorSettings WithCSS(string css)
Define CSS used to find elements. Browser only.
Definition Selector.cs:168
bool SimulateMouse
Simulate moving the mouse to interact with this element?
Definition Selector.cs:933
IAllowSelectorSettings WithOffsetY(int offsetY)
Define the y offset from the Top Left corner to perform clicks.
Definition Selector.cs:355
IAllowSelectorSettings WithHRef(string HRefFullOrPartial)
Found elements must carry this href, in full or in part, in order to interact with them....
Definition Selector.cs:595
IAllowSelectorSettings WithSearchForSelector(bool searchForElement)
Search for a matching image when using hardware emulation or image matching. Finding an element on p...
Definition Selector.cs:299
IAllowSelectorSettings MatchSrcRegex(string srcToMatch)
Found elements must match the src regular expression supplied in order to interact with them.
Definition Selector.cs:483
string Name
The name you gave this selector, or one assigned by GPAL [selector1, selector2...] Used in Informati...
Definition Selector.cs:870
IAllowSelectorSettings WithStopOnNotFound(bool stopOnNotFound)
Stop the workflow if this selector is not found.
Definition Selector.cs:555
int OffsetX
X offset from the top left corner to interact with the element, image match included....
Definition Selector.cs:807
IAllowSelectorSettings WithHardware
Interact with this element using hardware emulation.
Definition Selector.cs:612
An entry defining a selector locator, a selector path.
Settings for the current selector. Use this only for debugging.