askui 0.2.0 → 0.2.3

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.
Files changed (79) hide show
  1. package/README.md +2 -2
  2. package/bin/askui-postinstall +35 -0
  3. package/dist/cjs/core/model/test-case-dto/index.js +1 -3
  4. package/dist/cjs/core/model/test-case-dto/test-step.d.ts +3 -7
  5. package/dist/cjs/core/model/test-case-dto/test-step.js +0 -12
  6. package/dist/cjs/core/ui-control-commands/control-command.d.ts +1 -0
  7. package/dist/cjs/core/ui-control-commands/control-command.js +5 -0
  8. package/dist/cjs/core/ui-control-commands/input-event.d.ts +1 -2
  9. package/dist/cjs/core/ui-control-commands/input-event.js +0 -1
  10. package/dist/cjs/execution/dsl.d.ts +51 -1
  11. package/dist/cjs/execution/dsl.js +67 -10
  12. package/dist/cjs/execution/execution-runtime.d.ts +2 -0
  13. package/dist/cjs/execution/execution-runtime.js +27 -15
  14. package/dist/cjs/execution/inference-client.d.ts +1 -1
  15. package/dist/cjs/execution/inference-client.js +1 -1
  16. package/dist/cjs/execution/read-environment-credentials.js +4 -4
  17. package/dist/cjs/execution/read-environment-credentials.spec.js +2 -2
  18. package/dist/cjs/execution/ui-control-client.d.ts +46 -1
  19. package/dist/cjs/execution/ui-control-client.js +56 -6
  20. package/dist/cjs/execution/ui-controller-client-interface.d.ts +1 -1
  21. package/dist/cjs/lib/copy-example-project.js +2 -1
  22. package/dist/cjs/lib/download-binaries.js +2 -1
  23. package/dist/cjs/lib/ui-controller-facade.js +1 -1
  24. package/dist/cjs/lib/ui-controller-linux.js +2 -2
  25. package/dist/cjs/utils/analytics/analytics.js +7 -1
  26. package/dist/cjs/utils/analytics/installation-timestamp-create-error.d.ts +4 -0
  27. package/dist/cjs/utils/analytics/installation-timestamp-create-error.js +9 -0
  28. package/dist/cjs/utils/analytics/installation-timestamp-get-error.d.ts +4 -0
  29. package/dist/cjs/utils/analytics/installation-timestamp-get-error.js +9 -0
  30. package/dist/cjs/utils/analytics/installation-timestamp.d.ts +7 -0
  31. package/dist/cjs/utils/analytics/installation-timestamp.js +68 -0
  32. package/dist/cjs/utils/http/credentials.d.ts +1 -1
  33. package/dist/cjs/utils/http/credentials.js +1 -1
  34. package/dist/cjs/utils/http/credentials.spec.js +2 -2
  35. package/dist/cjs/utils/path.d.ts +1 -0
  36. package/dist/cjs/utils/path.js +11 -0
  37. package/dist/esm/core/model/test-case-dto/index.js +0 -1
  38. package/dist/esm/core/model/test-case-dto/test-step.d.ts +3 -7
  39. package/dist/esm/core/model/test-case-dto/test-step.js +1 -10
  40. package/dist/esm/core/ui-control-commands/control-command.d.ts +1 -0
  41. package/dist/esm/core/ui-control-commands/control-command.js +5 -0
  42. package/dist/esm/core/ui-control-commands/input-event.d.ts +1 -2
  43. package/dist/esm/core/ui-control-commands/input-event.js +0 -1
  44. package/dist/esm/execution/dsl.d.ts +51 -1
  45. package/dist/esm/execution/dsl.js +67 -10
  46. package/dist/esm/execution/execution-runtime.d.ts +2 -0
  47. package/dist/esm/execution/execution-runtime.js +27 -15
  48. package/dist/esm/execution/inference-client.d.ts +1 -1
  49. package/dist/esm/execution/inference-client.js +1 -1
  50. package/dist/esm/execution/read-environment-credentials.js +4 -4
  51. package/dist/esm/execution/read-environment-credentials.spec.js +2 -2
  52. package/dist/esm/execution/ui-control-client.d.ts +46 -1
  53. package/dist/esm/execution/ui-control-client.js +57 -7
  54. package/dist/esm/execution/ui-controller-client-interface.d.ts +1 -1
  55. package/dist/esm/lib/copy-example-project.js +2 -1
  56. package/dist/esm/lib/download-binaries.js +2 -1
  57. package/dist/esm/lib/ui-controller-facade.js +1 -1
  58. package/dist/esm/lib/ui-controller-linux.js +2 -2
  59. package/dist/esm/utils/analytics/analytics.js +7 -1
  60. package/dist/esm/utils/analytics/installation-timestamp-create-error.d.ts +4 -0
  61. package/dist/esm/utils/analytics/installation-timestamp-create-error.js +5 -0
  62. package/dist/esm/utils/analytics/installation-timestamp-get-error.d.ts +4 -0
  63. package/dist/esm/utils/analytics/installation-timestamp-get-error.js +5 -0
  64. package/dist/esm/utils/analytics/installation-timestamp.d.ts +7 -0
  65. package/dist/esm/utils/analytics/installation-timestamp.js +61 -0
  66. package/dist/esm/utils/http/credentials.d.ts +1 -1
  67. package/dist/esm/utils/http/credentials.js +1 -1
  68. package/dist/esm/utils/http/credentials.spec.js +2 -2
  69. package/dist/esm/utils/path.d.ts +1 -0
  70. package/dist/esm/utils/path.js +4 -0
  71. package/package.json +12 -4
  72. package/dist/cjs/utils/base_64_image/base-64-image-path-error.d.ts +0 -4
  73. package/dist/cjs/utils/base_64_image/base-64-image-path-error.js +0 -11
  74. package/dist/cjs/utils/image-resize-errors/invalid-base64-image-error.d.ts +0 -3
  75. package/dist/cjs/utils/image-resize-errors/invalid-base64-image-error.js +0 -7
  76. package/dist/esm/utils/base_64_image/base-64-image-path-error.d.ts +0 -4
  77. package/dist/esm/utils/base_64_image/base-64-image-path-error.js +0 -7
  78. package/dist/esm/utils/image-resize-errors/invalid-base64-image-error.d.ts +0 -3
  79. package/dist/esm/utils/image-resize-errors/invalid-base64-image-error.js +0 -3
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
2
  /* eslint-disable @typescript-eslint/naming-convention */
3
3
  /* eslint-disable max-classes-per-file */
4
+ /* eslint-disable max-len */
4
5
  // Autogenerated from typescript.template file
5
6
  class FluentBase {
6
7
  constructor(prev) {
@@ -646,6 +647,15 @@ export class FluentFilters extends FluentBase {
646
647
  /**
647
648
  * Filters for an UI element 'icon'.
648
649
  *
650
+ * You can combine it with the 'withText' command to look for a specific icon.
651
+ *
652
+ * **Examples:**
653
+ * ```typescript
654
+ * icon().withText('plus')
655
+ * ```
656
+ *
657
+ * Note: This is an alpha feature. The prediction of the icon name is sometimes unstable. Use custom elements as an alternative.
658
+ *
649
659
  * @return {FluentFiltersOrRelations}
650
660
  */
651
661
  icon() {
@@ -691,7 +701,26 @@ export class FluentFilters extends FluentBase {
691
701
  * @return {FluentFiltersOrRelations}
692
702
  */
693
703
  withText(text) {
694
- this._textStr = `with text "${text}"`;
704
+ this._textStr = `with text <|string|>${text}<|string|>`;
705
+ return new FluentFiltersOrRelations(this);
706
+ }
707
+ /**
708
+ * Filters for texts, which match the regex pattern.
709
+ *
710
+ * **Examples:**
711
+ *
712
+ * ```typescript
713
+ * 'The rain in Spain' === withTextRegex('\b[Ss]\w+') => true
714
+ * 'The rain in Portugal' === withTextRegex('\b[Ss]\w+') => false
715
+ * 'The rain in switzerland' === withTextRegex('\b[Ss]\w+') => true
716
+ * ```
717
+ *
718
+ * @param {string} regex_pattern - An regex pattern
719
+ *
720
+ * @return {FluentFiltersOrRelations}
721
+ */
722
+ withTextRegex(regex_pattern) {
723
+ this._textStr = `match regex pattern <|string|>${regex_pattern}<|string|>`;
695
724
  return new FluentFiltersOrRelations(this);
696
725
  }
697
726
  /**
@@ -713,7 +742,7 @@ export class FluentFilters extends FluentBase {
713
742
  * @return {FluentFiltersOrRelations}
714
743
  */
715
744
  withExactText(text) {
716
- this._textStr = `equals text "${text}"`;
745
+ this._textStr = `equals text <|string|>${text}<|string|>`;
717
746
  return new FluentFiltersOrRelations(this);
718
747
  }
719
748
  /**
@@ -731,7 +760,7 @@ export class FluentFilters extends FluentBase {
731
760
  * @return {FluentFiltersOrRelations}
732
761
  */
733
762
  containsText(text) {
734
- this._textStr = `contain text "${text}"`;
763
+ this._textStr = `contain text <|string|>${text}<|string|>`;
735
764
  return new FluentFiltersOrRelations(this);
736
765
  }
737
766
  /**
@@ -1528,6 +1557,15 @@ export class FluentFiltersCondition extends FluentBase {
1528
1557
  /**
1529
1558
  * Filters for an UI element 'icon'.
1530
1559
  *
1560
+ * You can combine it with the 'withText' command to look for a specific icon.
1561
+ *
1562
+ * **Examples:**
1563
+ * ```typescript
1564
+ * icon().withText('plus')
1565
+ * ```
1566
+ *
1567
+ * Note: This is an alpha feature. The prediction of the icon name is sometimes unstable. Use custom elements as an alternative.
1568
+ *
1531
1569
  * @return {FluentFiltersOrRelationsCondition}
1532
1570
  */
1533
1571
  icon() {
@@ -1573,7 +1611,26 @@ export class FluentFiltersCondition extends FluentBase {
1573
1611
  * @return {FluentFiltersOrRelationsCondition}
1574
1612
  */
1575
1613
  withText(text) {
1576
- this._textStr = `with text "${text}"`;
1614
+ this._textStr = `with text <|string|>${text}<|string|>`;
1615
+ return new FluentFiltersOrRelationsCondition(this);
1616
+ }
1617
+ /**
1618
+ * Filters for texts, which match the regex pattern.
1619
+ *
1620
+ * **Examples:**
1621
+ *
1622
+ * ```typescript
1623
+ * 'The rain in Spain' === withTextRegex('\b[Ss]\w+') => true
1624
+ * 'The rain in Portugal' === withTextRegex('\b[Ss]\w+') => false
1625
+ * 'The rain in switzerland' === withTextRegex('\b[Ss]\w+') => true
1626
+ * ```
1627
+ *
1628
+ * @param {string} regex_pattern - An regex pattern
1629
+ *
1630
+ * @return {FluentFiltersOrRelationsCondition}
1631
+ */
1632
+ withTextRegex(regex_pattern) {
1633
+ this._textStr = `match regex pattern <|string|>${regex_pattern}<|string|>`;
1577
1634
  return new FluentFiltersOrRelationsCondition(this);
1578
1635
  }
1579
1636
  /**
@@ -1595,7 +1652,7 @@ export class FluentFiltersCondition extends FluentBase {
1595
1652
  * @return {FluentFiltersOrRelationsCondition}
1596
1653
  */
1597
1654
  withExactText(text) {
1598
- this._textStr = `equals text "${text}"`;
1655
+ this._textStr = `equals text <|string|>${text}<|string|>`;
1599
1656
  return new FluentFiltersOrRelationsCondition(this);
1600
1657
  }
1601
1658
  /**
@@ -1613,7 +1670,7 @@ export class FluentFiltersCondition extends FluentBase {
1613
1670
  * @return {FluentFiltersOrRelationsCondition}
1614
1671
  */
1615
1672
  containsText(text) {
1616
- this._textStr = `contain text "${text}"`;
1673
+ this._textStr = `contain text <|string|>${text}<|string|>`;
1617
1674
  return new FluentFiltersOrRelationsCondition(this);
1618
1675
  }
1619
1676
  /**
@@ -1860,11 +1917,11 @@ export class FluentCommand extends FluentBase {
1860
1917
  * @return {FluentFilters}
1861
1918
  */
1862
1919
  typeIn(text) {
1863
- this._textStr = `Type "${text}" in`;
1920
+ this._textStr = `Type <|string|>${text}<|string|> in`;
1864
1921
  return new FluentFilters(this);
1865
1922
  }
1866
1923
  /**
1867
- * Moves mouse to the filtered element and scrolls in the x and y direction
1924
+ * Moves mouse to the filtered element and scrolls in the x and y direction.
1868
1925
  *
1869
1926
  * @param {number} x_offset - A (positive/negative) x direction.
1870
1927
  * @param {number} y_offset - A (positive/negative) y direction.
@@ -1908,7 +1965,7 @@ export class FluentCommand extends FluentBase {
1908
1965
  * @return {Exec}
1909
1966
  */
1910
1967
  type(text) {
1911
- this._textStr = `Type "${text}"`;
1968
+ this._textStr = `Type <|string|>${text}<|string|>`;
1912
1969
  return new Exec(this);
1913
1970
  }
1914
1971
  /**
@@ -1957,7 +2014,7 @@ export class FluentCommand extends FluentBase {
1957
2014
  * @return {Exec}
1958
2015
  */
1959
2016
  execOnShell(shell_command) {
1960
- this._textStr = `Execute shell command "${shell_command}"`;
2017
+ this._textStr = `Execute shell command <|string|>${shell_command}<|string|>`;
1961
2018
  return new Exec(this);
1962
2019
  }
1963
2020
  /**
@@ -8,6 +8,7 @@ export declare class ExecutionRuntime {
8
8
  private inferenceClient;
9
9
  constructor(uiControllerClient: UiControllerClient, inferenceClient: InferenceClient);
10
10
  executeTestStep(step: TestStep): Promise<void>;
11
+ private requestControl;
11
12
  /**
12
13
  * @param {TestStep} step - Test step used for predicting command.
13
14
  */
@@ -20,6 +21,7 @@ export declare class ExecutionRuntime {
20
21
  * --> retry with linear back-off
21
22
  */
22
23
  private predictCommandWithRetry;
24
+ private getImageIfRequired;
23
25
  private predictCommand;
24
26
  annotateInteractively(): Promise<void>;
25
27
  takeScreenshotIfImageisNotProvided(imagePath?: string): Promise<string>;
@@ -27,6 +27,11 @@ export class ExecutionRuntime {
27
27
  yield this.executeCommand(step);
28
28
  });
29
29
  }
30
+ requestControl(controlCommand) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ yield this.uiControllerClient.requestControl(controlCommand);
33
+ });
34
+ }
30
35
  /**
31
36
  * @param {TestStep} step - Test step used for predicting command.
32
37
  */
@@ -35,15 +40,13 @@ export class ExecutionRuntime {
35
40
  return __awaiter(this, void 0, void 0, function* () {
36
41
  const controlCommand = yield this.predictCommandWithRetry(step);
37
42
  if (controlCommand.code === ControlCommandCode.OK) {
38
- yield this.uiControllerClient.requestControl(controlCommand);
43
+ return this.requestControl(controlCommand);
39
44
  }
40
- else if (controlCommand.tryToRepeat) {
41
- yield this.uiControllerClient.requestControl(controlCommand);
42
- this.executeCommandRepeatedly(step);
43
- }
44
- else {
45
- throw new ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
45
+ if (controlCommand.tryToRepeat) {
46
+ yield this.requestControl(controlCommand);
47
+ return this.executeCommandRepeatedly(step);
46
48
  }
49
+ throw new ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
47
50
  });
48
51
  }
49
52
  executeCommandRepeatedly(step) {
@@ -60,8 +63,8 @@ export class ExecutionRuntime {
60
63
  if (controlCommand.code === ControlCommandCode.OK) {
61
64
  break;
62
65
  }
63
- else if (controlCommand.tryToRepeat) {
64
- yield this.uiControllerClient.requestControl(controlCommand);
66
+ if (controlCommand.tryToRepeat) {
67
+ yield this.requestControl(controlCommand);
65
68
  }
66
69
  else {
67
70
  throw new ControlCommandError(((_a = controlCommand.actions[0]) === null || _a === void 0 ? void 0 : _a.text) || '');
@@ -91,15 +94,24 @@ export class ExecutionRuntime {
91
94
  return command;
92
95
  });
93
96
  }
97
+ getImageIfRequired(instruction) {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ const isImageRequired = yield this.inferenceClient.isImageRequired(instruction);
100
+ if (!isImageRequired) {
101
+ return undefined;
102
+ }
103
+ const screenshotResponse = yield this.uiControllerClient.requestScreenshot();
104
+ return screenshotResponse.data.image;
105
+ });
106
+ }
94
107
  predictCommand(step) {
95
108
  return __awaiter(this, void 0, void 0, function* () {
96
- const isImageRequired = yield this.inferenceClient.isImageRequired(step.instruction);
97
- let image;
98
- if (isImageRequired) {
99
- const screenshotResponse = yield this.uiControllerClient.requestScreenshot();
100
- image = screenshotResponse.data.image;
109
+ const image = yield this.getImageIfRequired(step.instruction);
110
+ const controlCommand = yield this.inferenceClient.predictControlCommand(step.instruction, step.customElements, image);
111
+ if (step.secretText !== undefined) {
112
+ controlCommand.setTextToBeTyped(step.secretText);
101
113
  }
102
- return this.inferenceClient.predictControlCommand(step.instruction, step.customElements, image);
114
+ return controlCommand;
103
115
  });
104
116
  }
105
117
  annotateInteractively() {
@@ -8,6 +8,6 @@ export declare class InferenceClient {
8
8
  constructor(url: string, httpClient: HttpClientGot);
9
9
  isImageRequired(instruction: string): Promise<boolean>;
10
10
  private resizeIfNeeded;
11
- predictControlCommand(instruction: string, customElements: CustomElement[], image?: string): Promise<ControlCommand>;
11
+ predictControlCommand(instruction: string, customElements?: CustomElement[], image?: string): Promise<ControlCommand>;
12
12
  predictImageAnnotation(image: string, customElements?: CustomElement[]): Promise<Annotation>;
13
13
  }
@@ -35,7 +35,7 @@ export class InferenceClient {
35
35
  return resizeBase64ImageWithSameRatio(image);
36
36
  });
37
37
  }
38
- predictControlCommand(instruction, customElements, image) {
38
+ predictControlCommand(instruction, customElements = [], image) {
39
39
  return __awaiter(this, void 0, void 0, function* () {
40
40
  const resizedImage = yield this.resizeIfNeeded(customElements, image);
41
41
  const httpBody = {
@@ -1,12 +1,12 @@
1
1
  import { logger } from '../lib';
2
2
  export function envCredentials() {
3
3
  const envToken = process.env['ASKUI_TOKEN'];
4
- const envTenant = process.env['ASKUI_TENANT'];
4
+ const envWorkspaceId = process.env['ASKUI_WORKSPACE_ID'];
5
5
  const envEmail = process.env['ASKUI_EMAIL'];
6
- if (envToken && envTenant && envEmail) {
7
- logger.info('Credentials are used from ENV variables: ASKUI_TOKEN, ASKUI_TENANT and ASKUI_EMAIL');
6
+ if (envToken && envWorkspaceId && envEmail) {
7
+ logger.info('Credentials are used from ENV variables: ASKUI_TOKEN, ASKUI_WORKSPACE_ID and ASKUI_EMAIL');
8
8
  return {
9
- tenant: envTenant,
9
+ workspaceId: envWorkspaceId,
10
10
  email: envEmail,
11
11
  token: envToken,
12
12
  };
@@ -2,9 +2,9 @@ import { envCredentials } from './read-environment-credentials';
2
2
  describe('envCredentials()', () => {
3
3
  test('should read the credentials from the environment variables', () => {
4
4
  process.env['ASKUI_TOKEN'] = 'token';
5
- process.env['ASKUI_TENANT'] = 'tenant';
5
+ process.env['ASKUI_WORKSPACE_ID'] = 'id123';
6
6
  process.env['ASKUI_EMAIL'] = 'name@tenant.com';
7
7
  const credentialsFromTheEnv = envCredentials();
8
- expect(credentialsFromTheEnv).toStrictEqual({ tenant: 'tenant', email: 'name@tenant.com', token: 'token' });
8
+ expect(credentialsFromTheEnv).toStrictEqual({ workspaceId: 'id123', email: 'name@tenant.com', token: 'token' });
9
9
  });
10
10
  });
@@ -1,5 +1,5 @@
1
1
  import { CustomElementJson } from '../core/model/test-case-dto';
2
- import { Executable, FluentCommand } from './dsl';
2
+ import { Exec, Executable, FluentCommand, FluentFilters } from './dsl';
3
3
  import { UiControllerClientConnectionState } from './ui-controller-client-connection-state';
4
4
  import { Annotation } from '../core/annotation/annotation';
5
5
  import { AnnotationRequest } from '../core/model/annotation-result/annotation-interface';
@@ -18,6 +18,51 @@ export declare class UiControlClient extends FluentCommand {
18
18
  annotate(annotationRequest?: AnnotationRequest): Promise<Annotation>;
19
19
  annotateInteractively(): Promise<void>;
20
20
  exec(instruction: string, customElementJson?: CustomElementJson[]): Promise<void>;
21
+ private secretText;
22
+ /**
23
+ * Types a text inside the filtered element.
24
+ *
25
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
26
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
27
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
28
+ * This should not change the quality of the prediction of the askui Inference server. In this
29
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
30
+ *
31
+ * @param {string} text - A text to type.
32
+ * @param {Object} [options]
33
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
34
+ * logs of askui nor sent over to askui Inference for prediction.
35
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
36
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
37
+ *
38
+ * @return {FluentFilters}
39
+ */
40
+ typeIn(text: string, { isSecret, secretMask }?: {
41
+ isSecret?: boolean | undefined;
42
+ secretMask?: string | undefined;
43
+ }): FluentFilters;
44
+ /**
45
+ * Types a text at the current position.
46
+ *
47
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
48
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
49
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
50
+ * This should not change the quality of the prediction of the askui Inference server. In this
51
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
52
+ *
53
+ * @param {string} text - A text to type.
54
+ * @param {Object} options
55
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
56
+ * logs of askui nor sent over to askui Inference for prediction.
57
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
58
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
59
+ *
60
+ * @return {Exec}
61
+ */
62
+ type(text: string, { isSecret, secretMask }?: {
63
+ isSecret?: boolean | undefined;
64
+ secretMask?: string | undefined;
65
+ }): Exec;
21
66
  /**
22
67
  * Waits for `<delayInMs>` ms, e.g., 1000 ms. The exact delay may be a little longer
23
68
  * than `<delayInMs>` but never shorter than that.
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { CustomElement } from '../core/model/test-case-dto';
11
- import { FluentCommand } from './dsl';
11
+ import { FluentCommand, } from './dsl';
12
12
  import { HttpClientGot } from '../utils/http/http-client-got';
13
13
  import { UiControllerClient } from './ui-controller-client';
14
14
  import { ExecutionRuntime } from './execution-runtime';
@@ -20,12 +20,13 @@ import { AnnotationLevel } from './annotation-level';
20
20
  import { UiControlClientError } from './ui-control-client-error';
21
21
  import { envCredentials } from './read-environment-credentials';
22
22
  import { Analytics } from '../utils/analytics';
23
- const getClientArgsWithDefaults = (clientArgs = {}) => (Object.assign({ uiControllerUrl: 'http://localhost:6769', inferenceServerUrl: 'https://inference.askui.com', annotationLevel: AnnotationLevel.DISABLED }, clientArgs));
23
+ const getClientArgsWithDefaults = (clientArgs = {}) => (Object.assign({ uiControllerUrl: 'http://127.0.0.1:6769', inferenceServerUrl: 'https://inference.askui.com', annotationLevel: AnnotationLevel.DISABLED }, clientArgs));
24
24
  export class UiControlClient extends FluentCommand {
25
25
  constructor(httpClient, clientArgs) {
26
26
  super();
27
27
  this.httpClient = httpClient;
28
28
  this.clientArgs = clientArgs;
29
+ this.secretText = undefined;
29
30
  }
30
31
  static build(clientArgs) {
31
32
  return __awaiter(this, void 0, void 0, function* () {
@@ -85,16 +86,15 @@ export class UiControlClient extends FluentCommand {
85
86
  }
86
87
  });
87
88
  }
88
- exec(instruction, customElementJson) {
89
+ exec(instruction, customElementJson = []) {
89
90
  return __awaiter(this, void 0, void 0, function* () {
90
- let customElements = [];
91
- if (customElementJson !== undefined) {
92
- customElements = yield CustomElement.fromJsonListWithImagePathOrImage(customElementJson);
93
- }
91
+ const customElements = yield CustomElement.fromJsonListWithImagePathOrImage(customElementJson);
92
+ const { secretText } = this;
94
93
  try {
95
94
  yield this.executionRuntime.executeTestStep({
96
95
  instruction,
97
96
  customElements,
97
+ secretText,
98
98
  });
99
99
  yield this.annotateByDefault(TestStepState.PASSED, customElements);
100
100
  return yield Promise.resolve();
@@ -105,6 +105,56 @@ export class UiControlClient extends FluentCommand {
105
105
  }
106
106
  });
107
107
  }
108
+ /**
109
+ * Types a text inside the filtered element.
110
+ *
111
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
112
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
113
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
114
+ * This should not change the quality of the prediction of the askui Inference server. In this
115
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
116
+ *
117
+ * @param {string} text - A text to type.
118
+ * @param {Object} [options]
119
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
120
+ * logs of askui nor sent over to askui Inference for prediction.
121
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
122
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
123
+ *
124
+ * @return {FluentFilters}
125
+ */
126
+ typeIn(text, { isSecret = false, secretMask = '****' } = {}) {
127
+ if (isSecret) {
128
+ this.secretText = text;
129
+ return super.typeIn(secretMask);
130
+ }
131
+ return super.typeIn(text);
132
+ }
133
+ /**
134
+ * Types a text at the current position.
135
+ *
136
+ * By default, the `text` is included in the logs and sent over to the askui Inference server to
137
+ * predict in which context the typing has to occur. You can exclude the `text` from the logs
138
+ * and the request to the askui Inference server setting `options.isSecret` to `true`.
139
+ * This should not change the quality of the prediction of the askui Inference server. In this
140
+ * case, `options.secretMask` is included in logs and sent over instead of the `text`.
141
+ *
142
+ * @param {string} text - A text to type.
143
+ * @param {Object} options
144
+ * @param {boolean} [options.isSecret = false] - If set to `true`, `text` is neither included in
145
+ * logs of askui nor sent over to askui Inference for prediction.
146
+ * @param {string} [options.secretMask = '****'] - If `options.isSecret` is set to `true`, this
147
+ * is included in logs and sent over to askui Inference for prediction instead of the `text`.
148
+ *
149
+ * @return {Exec}
150
+ */
151
+ type(text, { isSecret = false, secretMask = '****' } = {}) {
152
+ if (isSecret) {
153
+ this.secretText = text;
154
+ return super.type(secretMask);
155
+ }
156
+ return super.type(text);
157
+ }
108
158
  /**
109
159
  * Waits for `<delayInMs>` ms, e.g., 1000 ms. The exact delay may be a little longer
110
160
  * than `<delayInMs>` but never shorter than that.
@@ -3,7 +3,7 @@ import { AnnotationLevel } from './annotation-level';
3
3
  /**
4
4
  * Configuration options for the askui UI Control Client
5
5
  *
6
- * @param {string} uiControllerUrl - Default: http://localhost:6769
6
+ * @param {string} uiControllerUrl - Default: http://127.0.0.1:6769
7
7
  * The adress of the askui UI Controller server.
8
8
  * @param {string} inferenceClientUrl - Default: https://inference.askui.com`
9
9
  * Address of the askui Inference server.
@@ -1,6 +1,7 @@
1
1
  import { Command } from 'commander';
2
2
  import path from 'path';
3
3
  import fs from 'fs-extra';
4
+ import { getPathToNodeModulesRoot } from '../utils/path';
4
5
  const createProgram = () => {
5
6
  const program = new Command('askui');
6
7
  program.usage('<command> [options]');
@@ -8,7 +9,7 @@ const createProgram = () => {
8
9
  };
9
10
  function copyExampleProject() {
10
11
  const exampleProjectPath = path.join('example_projects_templates', 'typescript_jest');
11
- fs.copySync(path.join(__dirname, '..', '..', exampleProjectPath), '.');
12
+ fs.copySync(path.join(getPathToNodeModulesRoot(), exampleProjectPath), '.');
12
13
  }
13
14
  export function init(argv) {
14
15
  const args = argv || process.argv;
@@ -2,6 +2,7 @@ import fs from 'fs';
2
2
  import got from 'got';
3
3
  import os from 'os';
4
4
  import path from 'path';
5
+ import { getPathToNodeModulesRoot } from '../utils/path';
5
6
  import { logger } from './logger';
6
7
  var SupportedPlatform;
7
8
  (function (SupportedPlatform) {
@@ -28,7 +29,7 @@ function buildBinaryNotAvailbleError(binaryVersion) {
28
29
  return new Error(`It seems that the UI Controller version "${binaryVersion}" for your system "${platform()} ${os.arch}" is not availble, Please contact as at info@askui.com for more information`);
29
30
  }
30
31
  export function getBinaryPath(version) {
31
- return path.join(__dirname, '..', '..', 'release', version, ...binarySubPathsByPlatform[platform()]);
32
+ return path.join(getPathToNodeModulesRoot(), 'release', version, ...binarySubPathsByPlatform[platform()]);
32
33
  }
33
34
  function getBinaryDownloadUrl(binaryVersion) {
34
35
  const baseUrl = `https://askui-public.s3.eu-central-1.amazonaws.com/releases/askui-ui-controller/${binaryVersion}`;
@@ -123,7 +123,7 @@ export class UiControllerFacade {
123
123
  }
124
124
  catch (err) {
125
125
  throw new Error(`The UI Controller could not be started. Log file : ${this.serverLogFile}. ErrorReason: ${err}
126
- Check this website for more information: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems`);
126
+ Check this website for more information: https://docs.askui.com/docs/general/Troubleshooting`);
127
127
  }
128
128
  });
129
129
  }
@@ -24,7 +24,7 @@ export class UiControllerLinux extends UiControllerFacade {
24
24
  const runCommand = promisify(exec);
25
25
  const waylandStatus = yield runCommand('echo $WAYLAND_DISPLAY');
26
26
  if (waylandStatus.stdout.trim().includes('wayland')) {
27
- throw new WaylandError('Wayland is not supported: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#wayland');
27
+ throw new WaylandError('Wayland is not supported: https://docs.askui.com/docs/general/Troubleshooting/linux#wayland');
28
28
  }
29
29
  /* First we want to check if the user is using a debian distribution.
30
30
  * and in the following if libfuse2 is installed.
@@ -41,7 +41,7 @@ export class UiControllerLinux extends UiControllerFacade {
41
41
  yield runCommand('dpkg -s libfuse2 | grep Status');
42
42
  }
43
43
  catch (_a) {
44
- throw new LibfuseError('Libfuse2 package is missing: https://docs.askui.com/docs/general/Troubleshooting/askui-ui-controller-starting-problems#libfuse2');
44
+ throw new LibfuseError('Libfuse2 package is missing: https://docs.askui.com/docs/general/Troubleshooting/linux#libfuse2');
45
45
  }
46
46
  });
47
47
  }
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import os from 'os';
11
11
  import { UserIdentifier } from './user-identifier';
12
+ import { InstallationTimestamp } from './installation-timestamp';
12
13
  export class Analytics {
13
14
  constructor() {
14
15
  this.userIdentifier = new UserIdentifier();
@@ -16,10 +17,15 @@ export class Analytics {
16
17
  getAnalyticsHeaders() {
17
18
  return __awaiter(this, void 0, void 0, function* () {
18
19
  const userID = yield this.userIdentifier.userId();
19
- return {
20
+ const headers = {
20
21
  'askui-user-id': userID,
21
22
  'askui-user-agent': `os:${os.platform()};arch:${os.arch()}`,
22
23
  };
24
+ const askuiInstalledAt = yield InstallationTimestamp.get();
25
+ if (askuiInstalledAt) {
26
+ headers['askui-installed-at'] = askuiInstalledAt.toISOString();
27
+ }
28
+ return headers;
23
29
  });
24
30
  }
25
31
  }
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ export declare class InstallationTimestampCreateError extends Error {
3
+ constructor(err: NodeJS.ErrnoException);
4
+ }
@@ -0,0 +1,5 @@
1
+ export class InstallationTimestampCreateError extends Error {
2
+ constructor(err) {
3
+ super(`Installation timestamp could not be created. \n${err.message}`);
4
+ }
5
+ }
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ export declare class InstallationTimestampGetError extends Error {
3
+ constructor(err: NodeJS.ErrnoException);
4
+ }
@@ -0,0 +1,5 @@
1
+ export class InstallationTimestampGetError extends Error {
2
+ constructor(err) {
3
+ super(`Installation timestamp does not exist. Try reinstalling the lib to create it. \n${err.message}`);
4
+ }
5
+ }
@@ -0,0 +1,7 @@
1
+ export declare abstract class InstallationTimestamp {
2
+ private static fileName;
3
+ private static value?;
4
+ static create(): Promise<void>;
5
+ static get(): Promise<Date | null>;
6
+ private static getFromFile;
7
+ }