@testring/plugin-selenium-driver 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,11 @@ import {
3
3
  IBrowserProxyPlugin,
4
4
  SavePdfOptions,
5
5
  WindowFeaturesConfig,
6
- IWindowFeatures
6
+ IWindowFeatures,
7
+ Selector,
8
+ ShadowCssSelector,
9
+ isXpathSelector,
10
+ isShadowCssSelector
7
11
  } from '@testring/types';
8
12
 
9
13
  import {ChildProcess} from 'child_process';
@@ -187,6 +191,7 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
187
191
 
188
192
  if (this.config.host === undefined) {
189
193
  this.runLocalSelenium();
194
+ this.setupProcessCleanup();
190
195
  }
191
196
 
192
197
  this.initIntervals();
@@ -240,6 +245,19 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
240
245
  }
241
246
  }
242
247
 
248
+ private setupProcessCleanup() {
249
+ process.on('SIGINT', () => this.forceKillSelenium());
250
+ process.on('SIGTERM', () => this.forceKillSelenium());
251
+ // Note: SIGKILL cannot be caught or handled - it immediately terminates the process
252
+ }
253
+
254
+ private forceKillSelenium() {
255
+ if (this.localSelenium && !this.localSelenium.killed) {
256
+ this.logger.debug('Force killing Selenium process due to signal');
257
+ this.localSelenium.kill('SIGKILL');
258
+ }
259
+ }
260
+
243
261
  private stopAllSessions() {
244
262
  const clientsRequests: Promise<any>[] = [];
245
263
 
@@ -313,7 +331,11 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
313
331
  this.localSelenium = spawnWithPipes('java', seleniumArgs);
314
332
 
315
333
  this.waitForReadyState = new Promise((resolve, reject) => {
316
- setupProcessListeners(this.localSelenium!, resolve, reject, version, this.logger);
334
+ if (this.localSelenium) {
335
+ setupProcessListeners(this.localSelenium, resolve, reject, version, this.logger);
336
+ } else {
337
+ reject(new Error('Failed to spawn Selenium process'));
338
+ }
317
339
  });
318
340
 
319
341
  // Wait for the server to be ready
@@ -499,6 +521,95 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
499
521
  return client as BrowserObjectCustom;
500
522
  }
501
523
 
524
+ private async getElement(applicant: string, selector: Selector) {
525
+ await this.createClient(applicant);
526
+ const client = this.getBrowserClient(applicant);
527
+
528
+ if (isXpathSelector(selector)) {
529
+ return client.$(selector.xpath);
530
+ } else if (isShadowCssSelector(selector)) {
531
+ return this.getElementFromShadowCss(client, selector);
532
+ }
533
+
534
+ throw new Error('Unknown selector type');
535
+ }
536
+
537
+ private async getElementFromShadowCss(client: BrowserObjectCustom, selector: ShadowCssSelector) {
538
+ const {css, parentSelectors} = selector;
539
+
540
+ // Error first: validate selector structure
541
+ this.validateShadowCssSelector(selector);
542
+
543
+ try {
544
+ return await this.traverseShadowDom(client, css, parentSelectors);
545
+ } catch (error) {
546
+ // Provide more context in error messages
547
+ if (error instanceof Error) {
548
+ throw new Error(`Shadow DOM traversal failed: ${error.message}. Selector: ${JSON.stringify(selector)}`);
549
+ }
550
+ throw error;
551
+ }
552
+ }
553
+
554
+ private validateShadowCssSelector(selector: ShadowCssSelector): void {
555
+ const {css, parentSelectors} = selector;
556
+
557
+ if (!css || typeof css !== 'string') {
558
+ throw new Error('Shadow CSS selector must have a valid CSS string');
559
+ }
560
+
561
+ if (!Array.isArray(parentSelectors) || parentSelectors.length === 0) {
562
+ throw new Error('Shadow CSS selector must have at least one parent selector');
563
+ }
564
+
565
+ // Validate all parent selectors are non-empty strings
566
+ for (const [index, parentSelector] of parentSelectors.entries()) {
567
+ if (!parentSelector || typeof parentSelector !== 'string') {
568
+ throw new Error(`Parent selector at index ${index} must be a non-empty string`);
569
+ }
570
+ }
571
+ }
572
+
573
+ private async traverseToLastParentSelector(client: BrowserObjectCustom, parentSelectors: string[]) {
574
+ const [firstParentSelector, ...restParentSelectors] = parentSelectors;
575
+
576
+ // TypeScript assertion: we know firstParentSelector exists due to validation
577
+ if (!firstParentSelector) {
578
+ throw new Error('First parent selector is required');
579
+ }
580
+
581
+ // Get the first parent element
582
+ let currentElement = await client.$(firstParentSelector);
583
+
584
+ if (!currentElement) {
585
+ throw new Error(`Failed to find parent element with selector: ${firstParentSelector}`);
586
+ }
587
+
588
+ // Traverse through shadow DOM hierarchy
589
+ for (const parentSelector of restParentSelectors) {
590
+ const shadowElement = await currentElement.shadow$(parentSelector);
591
+ if (!shadowElement) {
592
+ throw new Error(`Failed to find shadow element with selector: ${parentSelector}`);
593
+ }
594
+ currentElement = shadowElement;
595
+ }
596
+
597
+ return currentElement;
598
+ }
599
+
600
+ private async traverseShadowDom(client: BrowserObjectCustom, css: string, parentSelectors: string[]) {
601
+ // Traverse to the last parent selector
602
+ const lastParentElement = await this.traverseToLastParentSelector(client, parentSelectors);
603
+
604
+ // Get the final target element within the shadow DOM
605
+ const targetElement = await lastParentElement.shadow$(css);
606
+ if (!targetElement) {
607
+ throw new Error(`Failed to find target element with CSS selector: ${css}`);
608
+ }
609
+
610
+ return targetElement;
611
+ }
612
+
502
613
  public async end(applicant: string) {
503
614
  await this.waitForReadyState;
504
615
 
@@ -638,24 +749,17 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
638
749
 
639
750
  public async click(
640
751
  applicant: string,
641
- selector: string,
752
+ selector: Selector,
642
753
  options?: ClickOptions,
643
754
  ) {
644
- await this.createClient(applicant);
645
- const client = this.getBrowserClient(applicant);
646
-
647
- const element = await client.$(selector);
755
+ const element = await this.getElement(applicant, selector);
648
756
  return options && Object.keys(options).length > 0
649
757
  ? element.click(options)
650
758
  : element.click();
651
759
  }
652
760
 
653
- public async getSize(applicant: string, selector: string) {
654
- await this.createClient(applicant);
655
- const client = this.getBrowserClient(applicant);
656
-
657
- const element = await client.$(selector);
658
-
761
+ public async getSize(applicant: string, selector: Selector) {
762
+ const element = await this.getElement(applicant, selector);
659
763
  return element.getSize();
660
764
  }
661
765
 
@@ -695,47 +799,35 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
695
799
 
696
800
  public async waitForExist(
697
801
  applicant: string,
698
- xpath: string,
802
+ selector: Selector,
699
803
  timeout: number,
700
804
  ) {
701
- await this.createClient(applicant);
702
- const client = this.getBrowserClient(applicant);
703
-
704
- const selector = await client.$(xpath);
705
- return selector.waitForExist({timeout});
805
+ const element = await this.getElement(applicant, selector);
806
+ return element.waitForExist({timeout});
706
807
  }
707
808
 
708
809
  public async waitForVisible(
709
810
  applicant: string,
710
- xpath: string,
811
+ selector: Selector,
711
812
  timeout: number,
712
813
  ) {
713
- await this.createClient(applicant);
714
- const client = this.getBrowserClient(applicant);
715
-
716
- const selector = await client.$(xpath);
717
- return selector.waitForDisplayed({timeout});
814
+ const element = await this.getElement(applicant, selector);
815
+ return element.waitForDisplayed({timeout});
718
816
  }
719
817
 
720
- public async isVisible(applicant: string, xpath: string) {
721
- await this.createClient(applicant);
722
- const client = this.getBrowserClient(applicant);
723
-
724
- const selector = await client.$(xpath);
725
- return selector.isDisplayed();
818
+ public async isVisible(applicant: string, selector: Selector) {
819
+ const element = await this.getElement(applicant, selector);
820
+ return element.isDisplayed();
726
821
  }
727
822
 
728
823
  public async moveToObject(
729
824
  applicant: string,
730
- xpath: string,
825
+ selector: Selector,
731
826
  xOffset = 0,
732
827
  yOffset = 0,
733
828
  ) {
734
- await this.createClient(applicant);
735
- const client = this.getBrowserClient(applicant);
736
-
737
- const selector = await client.$(xpath);
738
- return selector.moveTo({xOffset, yOffset});
829
+ const element = await this.getElement(applicant, selector);
830
+ return element.moveTo({xOffset, yOffset});
739
831
  }
740
832
 
741
833
  public async execute(applicant: string, fn: any, args: Array<any>) {
@@ -759,12 +851,9 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
759
851
  return client.getTitle();
760
852
  }
761
853
 
762
- public async clearValue(applicant: string, xpath: string) {
763
- await this.createClient(applicant);
764
- const client = this.getBrowserClient(applicant);
765
-
766
- const selector = await client.$(xpath);
767
- return selector.clearValue();
854
+ public async clearValue(applicant: string, selector: Selector) {
855
+ const element = await this.getElement(applicant, selector);
856
+ return element.clearValue();
768
857
  }
769
858
 
770
859
  public async keys(applicant: string, value: any) {
@@ -781,19 +870,29 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
781
870
  return client.getElementText(elementId);
782
871
  }
783
872
 
784
- public async elements(applicant: string, xpath: string) {
873
+ public async elements(applicant: string, selector: Selector) {
785
874
  await this.createClient(applicant);
786
875
  const client = this.getBrowserClient(applicant);
787
876
 
788
- const elements = (await client.findElements('xpath', xpath)) as unknown;
789
- return (elements as Array<Record<string, string>>).map((o) => {
790
- const keys = Object.keys(o);
791
- const firstKey = keys[0];
792
- if (firstKey === undefined) {
793
- return {ELEMENT: ''};
794
- }
795
- return {ELEMENT: o[firstKey]};
796
- });
877
+ if (isXpathSelector(selector)) {
878
+ const elements = (await client.findElements('xpath', selector.xpath)) as unknown;
879
+ return (elements as Array<Record<string, string>>).map((o) => {
880
+ const keys = Object.keys(o);
881
+ const firstKey = keys[0];
882
+ if (firstKey === undefined) {
883
+ return {ELEMENT: ''};
884
+ }
885
+ return {ELEMENT: o[firstKey]};
886
+ });
887
+ } else if (isShadowCssSelector(selector)) {
888
+ const lastParentElement = await this.traverseToLastParentSelector(client, selector.parentSelectors);
889
+ const elements = lastParentElement.shadow$$(selector.css);
890
+ return elements.map((element) => {
891
+ return {ELEMENT: element.elementId};
892
+ });
893
+ }
894
+
895
+ throw new Error('Unknown selector type');
797
896
  }
798
897
 
799
898
  public async frame(applicant: string, frameID: any) {
@@ -809,60 +908,42 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
809
908
  return client.switchToParentFrame();
810
909
  }
811
910
 
812
- public async getValue(applicant: string, xpath: string) {
813
- await this.createClient(applicant);
814
- const client = this.getBrowserClient(applicant);
815
-
816
- const selector = await client.$(xpath);
817
- return selector.getValue();
911
+ public async getValue(applicant: string, selector: Selector) {
912
+ const element = await this.getElement(applicant, selector);
913
+ return element.getValue();
818
914
  }
819
915
 
820
- public async setValue(applicant: string, xpath: string, value: any) {
821
- await this.createClient(applicant);
822
- const client = this.getBrowserClient(applicant);
823
-
824
- const selector = await client.$(xpath);
825
- return selector.setValue(value);
916
+ public async setValue(applicant: string, selector: Selector, value: any) {
917
+ const element = await this.getElement(applicant, selector);
918
+ return element.setValue(value);
826
919
  }
827
920
 
828
- public async selectByIndex(applicant: string, xpath: string, value: any) {
829
- await this.createClient(applicant);
830
- const client = this.getBrowserClient(applicant);
831
-
832
- const selector = await client.$(xpath);
833
- return selector.selectByIndex(value);
921
+ public async selectByIndex(applicant: string, selector: Selector, value: any) {
922
+ const element = await this.getElement(applicant, selector);
923
+ return element.selectByIndex(value);
834
924
  }
835
925
 
836
- public async selectByValue(applicant: string, xpath: string, value: any) {
837
- await this.createClient(applicant);
838
- const client = this.getBrowserClient(applicant);
839
-
840
- const selector = await client.$(xpath);
841
- return selector.selectByAttribute('value', value);
926
+ public async selectByValue(applicant: string, selector: Selector, value: any) {
927
+ const element = await this.getElement(applicant, selector);
928
+ return element.selectByAttribute('value', value);
842
929
  }
843
930
 
844
931
  public async selectByVisibleText(
845
932
  applicant: string,
846
- xpath: string,
933
+ selector: Selector,
847
934
  str: string,
848
935
  ) {
849
- await this.createClient(applicant);
850
- const client = this.getBrowserClient(applicant);
851
-
852
- const selector = await client.$(xpath);
853
- return selector.selectByVisibleText(str);
936
+ const element = await this.getElement(applicant, selector);
937
+ return element.selectByVisibleText(str);
854
938
  }
855
939
 
856
940
  public async getAttribute(
857
941
  applicant: string,
858
- xpath: string,
942
+ selector: Selector,
859
943
  attr: string,
860
944
  ): Promise<any> {
861
- await this.createClient(applicant);
862
- const client = this.getBrowserClient(applicant);
863
-
864
- const selector = await client.$(xpath);
865
- return selector.getAttribute(attr);
945
+ const element = await this.getElement(applicant, selector);
946
+ return element.getAttribute(attr);
866
947
  }
867
948
 
868
949
  public async windowHandleMaximize(applicant: string) {
@@ -872,37 +953,28 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
872
953
  return client.maximizeWindow();
873
954
  }
874
955
 
875
- public async isEnabled(applicant: string, xpath: string) {
876
- await this.createClient(applicant);
877
- const client = this.getBrowserClient(applicant);
878
-
879
- const selector = await client.$(xpath);
880
- return selector.isEnabled();
956
+ public async isEnabled(applicant: string, selector: Selector) {
957
+ const element = await this.getElement(applicant, selector);
958
+ return element.isEnabled();
881
959
  }
882
960
 
883
961
  public async scroll(
884
962
  applicant: string,
885
- xpath: string,
963
+ selector: Selector,
886
964
  xOffset: number,
887
965
  yOffset: number,
888
966
  ) {
889
- await this.createClient(applicant);
890
- const client = this.getBrowserClient(applicant);
891
-
892
- const element = await client.$(xpath);
967
+ const element = await this.getElement(applicant, selector);
893
968
  await element.scrollIntoView();
894
969
  return element.moveTo({xOffset, yOffset});
895
970
  }
896
971
 
897
972
  public async scrollIntoView(
898
973
  applicant: string,
899
- xpath: string,
974
+ selector: Selector,
900
975
  scrollIntoViewOptions?: boolean | null,
901
976
  ) {
902
- await this.createClient(applicant);
903
- const client = this.getBrowserClient(applicant);
904
-
905
- const element = await client.$(xpath);
977
+ const element = await this.getElement(applicant, selector);
906
978
  await element.scrollIntoView(
907
979
  scrollIntoViewOptions !== null ? scrollIntoViewOptions : undefined,
908
980
  );
@@ -950,14 +1022,11 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
950
1022
 
951
1023
  public async dragAndDrop(
952
1024
  applicant: string,
953
- xpathSource: string,
954
- xpathDestination: string,
1025
+ sourceSelector: Selector,
1026
+ destinationSelector: Selector,
955
1027
  ) {
956
- await this.createClient(applicant);
957
- const client = this.getBrowserClient(applicant);
958
-
959
- const sourceElement = await client.$(xpathSource);
960
- const destinationElement = await client.$(xpathDestination);
1028
+ const sourceElement = await this.getElement(applicant, sourceSelector);
1029
+ const destinationElement = await this.getElement(applicant, destinationSelector);
961
1030
  return sourceElement.dragAndDrop(destinationElement);
962
1031
  }
963
1032
 
@@ -995,12 +1064,9 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
995
1064
  return client.deleteAllCookies();
996
1065
  }
997
1066
 
998
- public async getHTML(applicant: string, xpath: string, b: any) {
999
- await this.createClient(applicant);
1000
- const client = this.getBrowserClient(applicant);
1001
-
1002
- const selector = await client.$(xpath);
1003
- return selector.getHTML(b);
1067
+ public async getHTML(applicant: string, selector: Selector, b: any) {
1068
+ const element = await this.getElement(applicant, selector);
1069
+ return element.getHTML(b);
1004
1070
  }
1005
1071
 
1006
1072
  public async getCurrentTabId(applicant: string) {
@@ -1054,28 +1120,19 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1054
1120
  return client.closeWindow();
1055
1121
  }
1056
1122
 
1057
- public async getTagName(applicant: string, xpath: string) {
1058
- await this.createClient(applicant);
1059
- const client = this.getBrowserClient(applicant);
1060
-
1061
- const selector = await client.$(xpath);
1062
- return selector.getTagName();
1123
+ public async getTagName(applicant: string, selector: Selector) {
1124
+ const element = await this.getElement(applicant, selector);
1125
+ return element.getTagName();
1063
1126
  }
1064
1127
 
1065
- public async isSelected(applicant: string, xpath: string) {
1066
- await this.createClient(applicant);
1067
- const client = this.getBrowserClient(applicant);
1068
-
1069
- const selector = await client.$(xpath);
1070
- return selector.isSelected();
1128
+ public async isSelected(applicant: string, selector: Selector) {
1129
+ const element = await this.getElement(applicant, selector);
1130
+ return element.isSelected();
1071
1131
  }
1072
1132
 
1073
- public async getText(applicant: string, xpath: string) {
1074
- await this.createClient(applicant);
1075
- const client = this.getBrowserClient(applicant);
1076
-
1077
- const selector = await client.$(xpath);
1078
- return selector.getText();
1133
+ public async getText(applicant: string, selector: Selector) {
1134
+ const element = await this.getElement(applicant, selector);
1135
+ return element.getText();
1079
1136
  }
1080
1137
 
1081
1138
  public async elementIdSelected(applicant: string, id: string) {
@@ -1104,13 +1161,10 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1104
1161
 
1105
1162
  public async getCssProperty(
1106
1163
  applicant: string,
1107
- xpath: string,
1164
+ selector: Selector,
1108
1165
  cssProperty: string,
1109
1166
  ): Promise<any> {
1110
- await this.createClient(applicant);
1111
- const client = this.getBrowserClient(applicant);
1112
-
1113
- const element = await client.$(xpath);
1167
+ const element = await this.getElement(applicant, selector);
1114
1168
  const property = await element.getCSSProperty(cssProperty);
1115
1169
  return property.value;
1116
1170
  }
@@ -1122,17 +1176,14 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1122
1176
  return client.getPageSource();
1123
1177
  }
1124
1178
 
1125
- public async isExisting(applicant: string, xpath: string) {
1126
- await this.createClient(applicant);
1127
- const client = this.getBrowserClient(applicant);
1128
-
1129
- const selector = await client.$(xpath);
1130
- return selector.isExisting();
1179
+ public async isExisting(applicant: string, selector: Selector) {
1180
+ const element = await this.getElement(applicant, selector);
1181
+ return element.isExisting();
1131
1182
  }
1132
1183
 
1133
1184
  public async waitForValue(
1134
1185
  applicant: string,
1135
- xpath: string,
1186
+ selector: Selector,
1136
1187
  timeout: number,
1137
1188
  reverse: boolean,
1138
1189
  ) {
@@ -1141,7 +1192,8 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1141
1192
 
1142
1193
  return client.waitUntil(
1143
1194
  async () => {
1144
- const elemValue = await (await client.$(xpath)).getValue();
1195
+ const element = await this.getElement(applicant, selector);
1196
+ const elemValue = await element.getValue();
1145
1197
  return reverse ? !elemValue : !!elemValue;
1146
1198
  },
1147
1199
  {timeout},
@@ -1150,7 +1202,7 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1150
1202
 
1151
1203
  public async waitForSelected(
1152
1204
  applicant: string,
1153
- xpath: string,
1205
+ selector: Selector,
1154
1206
  timeout: number,
1155
1207
  reverse: boolean,
1156
1208
  ) {
@@ -1159,7 +1211,8 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1159
1211
 
1160
1212
  return client.waitUntil(
1161
1213
  async () => {
1162
- const isSelected = await (await client.$(xpath)).isSelected();
1214
+ const element = await this.getElement(applicant, selector);
1215
+ const isSelected = await element.isSelected();
1163
1216
  return reverse ? !isSelected : isSelected;
1164
1217
  },
1165
1218
  {timeout},
@@ -1193,15 +1246,12 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1193
1246
 
1194
1247
  public async selectByAttribute(
1195
1248
  applicant: string,
1196
- xpath: string,
1249
+ selector: Selector,
1197
1250
  attribute: string,
1198
1251
  value: string,
1199
1252
  ) {
1200
- await this.createClient(applicant);
1201
- const client = this.getBrowserClient(applicant);
1202
-
1203
- const selector = await client.$(xpath);
1204
- return selector.selectByAttribute(attribute, value);
1253
+ const element = await this.getElement(applicant, selector);
1254
+ return element.selectByAttribute(attribute, value);
1205
1255
  }
1206
1256
 
1207
1257
  public async gridTestSession(applicant: string) {
@@ -1299,10 +1349,8 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1299
1349
  return client.getActiveElement();
1300
1350
  }
1301
1351
 
1302
- public async getLocation(applicant: string, xpath: string) {
1303
- await this.createClient(applicant);
1304
- const client = this.getBrowserClient(applicant);
1305
- const element = client.$(xpath);
1352
+ public async getLocation(applicant: string, selector: Selector) {
1353
+ const element = await this.getElement(applicant, selector);
1306
1354
  return element.getLocation();
1307
1355
  }
1308
1356
 
@@ -1329,82 +1377,58 @@ export class SeleniumPlugin implements IBrowserProxyPlugin {
1329
1377
 
1330
1378
  public async addValue(
1331
1379
  applicant: string,
1332
- xpath: string,
1380
+ selector: Selector,
1333
1381
  value: string | number,
1334
1382
  ) {
1335
- await this.createClient(applicant);
1336
- const client = this.getBrowserClient(applicant);
1337
-
1338
- const selector = await client.$(xpath);
1339
- return selector.addValue(value);
1383
+ const element = await this.getElement(applicant, selector);
1384
+ return element.addValue(value);
1340
1385
  }
1341
1386
 
1342
- public async doubleClick(applicant: string, xpath: string) {
1343
- await this.createClient(applicant);
1344
- const client = this.getBrowserClient(applicant);
1345
-
1346
- const selector = await client.$(xpath);
1347
- return selector.doubleClick();
1387
+ public async doubleClick(applicant: string, selector: Selector) {
1388
+ const element = await this.getElement(applicant, selector);
1389
+ return element.doubleClick();
1348
1390
  }
1349
1391
 
1350
- public async isClickable(applicant: string, xpath: string) {
1351
- await this.createClient(applicant);
1352
- const client = this.getBrowserClient(applicant);
1353
-
1354
- const selector = await client.$(xpath);
1355
- return selector.isClickable();
1392
+ public async isClickable(applicant: string, selector: Selector) {
1393
+ const element = await this.getElement(applicant, selector);
1394
+ return element.isClickable();
1356
1395
  }
1357
1396
 
1358
1397
  public async waitForClickable(
1359
1398
  applicant: string,
1360
- xpath: string,
1399
+ selector: Selector,
1361
1400
  timeout: number,
1362
1401
  ) {
1363
- await this.createClient(applicant);
1364
- const client = this.getBrowserClient(applicant);
1365
-
1366
- const selector = await client.$(xpath);
1367
- return selector.waitForClickable({timeout});
1402
+ const element = await this.getElement(applicant, selector);
1403
+ return element.waitForClickable({timeout});
1368
1404
  }
1369
1405
 
1370
- public async isFocused(applicant: string, xpath: string) {
1371
- await this.createClient(applicant);
1372
- const client = this.getBrowserClient(applicant);
1373
-
1374
- const selector = await client.$(xpath);
1375
- return selector.isFocused();
1406
+ public async isFocused(applicant: string, selector: Selector) {
1407
+ const element = await this.getElement(applicant, selector);
1408
+ return element.isFocused();
1376
1409
  }
1377
1410
 
1378
- public async isStable(applicant: string, xpath: string) {
1379
- await this.createClient(applicant);
1380
- const client = this.getBrowserClient(applicant);
1381
-
1382
- const selector = await client.$(xpath);
1383
- return selector.isStable();
1411
+ public async isStable(applicant: string, selector: Selector) {
1412
+ const element = await this.getElement(applicant, selector);
1413
+ return element.isStable();
1384
1414
  }
1385
1415
 
1386
1416
  public async waitForEnabled(
1387
1417
  applicant: string,
1388
- xpath: string,
1418
+ selector: Selector,
1389
1419
  timeout: number,
1390
1420
  ) {
1391
- await this.createClient(applicant);
1392
- const client = this.getBrowserClient(applicant);
1393
-
1394
- const selector = await client.$(xpath);
1395
- return selector.waitForEnabled({timeout});
1421
+ const element = await this.getElement(applicant, selector);
1422
+ return element.waitForEnabled({timeout});
1396
1423
  }
1397
1424
 
1398
1425
  public async waitForStable(
1399
1426
  applicant: string,
1400
- xpath: string,
1427
+ selector: Selector,
1401
1428
  timeout: number,
1402
1429
  ) {
1403
- await this.createClient(applicant);
1404
- const client = this.getBrowserClient(applicant);
1405
-
1406
- const selector = await client.$(xpath);
1407
- return selector.waitForStable({timeout});
1430
+ const element = await this.getElement(applicant, selector);
1431
+ return element.waitForStable({timeout});
1408
1432
  }
1409
1433
  }
1410
1434