testdriverai 6.0.16-canary.f0eefe0.0 → 6.0.16

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 (107) hide show
  1. package/agent/events.js +11 -1
  2. package/agent/index.js +9 -13
  3. package/agent/lib/censorship.js +70 -0
  4. package/debugger/index.html +2 -0
  5. package/docs/_scripts/link-replacer.js +164 -0
  6. package/docs/account/dashboard.mdx +5 -2
  7. package/docs/account/pricing.mdx +12 -5
  8. package/docs/account/projects.mdx +3 -2
  9. package/docs/account/team.mdx +7 -3
  10. package/docs/apps/chrome-extensions.mdx +8 -2
  11. package/docs/apps/desktop-apps.mdx +5 -5
  12. package/docs/apps/mobile-apps.mdx +7 -2
  13. package/docs/cli/overview.mdx +6 -6
  14. package/docs/commands/assert.mdx +9 -6
  15. package/docs/commands/hover-image.mdx +9 -6
  16. package/docs/commands/if.mdx +11 -6
  17. package/docs/commands/match-image.mdx +13 -6
  18. package/docs/commands/remember.mdx +10 -5
  19. package/docs/commands/run.mdx +8 -2
  20. package/docs/commands/type.mdx +11 -5
  21. package/docs/commands/wait-for-image.mdx +9 -3
  22. package/docs/commands/wait.mdx +9 -4
  23. package/docs/features/generation.mdx +1 -1
  24. package/docs/features/reusable-snippets.mdx +8 -5
  25. package/docs/features/selectorless.mdx +13 -6
  26. package/docs/features/visual-assertions.mdx +53 -39
  27. package/docs/getting-started/editing.mdx +1 -1
  28. package/docs/guide/assertions.mdx +12 -17
  29. package/docs/guide/code.mdx +2 -2
  30. package/docs/guide/lifecycle.mdx +3 -3
  31. package/docs/guide/locating.mdx +13 -6
  32. package/docs/guide/waiting.mdx +41 -32
  33. package/docs/interactive/assert.mdx +11 -0
  34. package/docs/interactive/generate.mdx +11 -0
  35. package/docs/interactive/run.mdx +8 -0
  36. package/docs/interactive/save.mdx +7 -0
  37. package/docs/interactive/undo.mdx +11 -3
  38. package/docs/overview/comparison.mdx +50 -49
  39. package/docs/overview/faq.mdx +40 -2
  40. package/docs/overview/performance.mdx +25 -25
  41. package/docs/overview/what-is-testdriver.mdx +24 -22
  42. package/docs/scenarios/ai-chatbot.mdx +6 -5
  43. package/docs/scenarios/cookie-banner.mdx +4 -1
  44. package/docs/scenarios/file-upload.mdx +7 -4
  45. package/docs/scenarios/form-filling.mdx +4 -1
  46. package/docs/scenarios/pdf-generation.mdx +5 -2
  47. package/docs/scenarios/spell-check.mdx +3 -3
  48. package/docs/security/agent.mdx +14 -2
  49. package/docs/security/platform.mdx +17 -5
  50. package/docs/snippets/calendar-link.mdx +4 -1
  51. package/docs/snippets/comments.mdx +1 -1
  52. package/docs/snippets/gitignore-warning.mdx +6 -3
  53. package/docs/snippets/lifecycle-warning.mdx +6 -1
  54. package/docs/snippets/tests/assert-replay.mdx +5 -1
  55. package/docs/snippets/tests/exec-js-replay.mdx +5 -1
  56. package/docs/snippets/tests/exec-shell-replay.mdx +5 -1
  57. package/docs/snippets/tests/hover-image-replay.mdx +5 -1
  58. package/docs/snippets/tests/hover-image-yaml.mdx +2 -2
  59. package/docs/snippets/tests/hover-text-replay.mdx +5 -1
  60. package/docs/snippets/tests/hover-text-with-description-replay.mdx +5 -2
  61. package/docs/snippets/tests/hover-text-with-description-yaml.mdx +2 -2
  62. package/docs/snippets/tests/match-image-replay.mdx +5 -1
  63. package/docs/snippets/tests/match-image-yaml.mdx +2 -2
  64. package/docs/snippets/tests/press-keys-replay.mdx +5 -1
  65. package/docs/snippets/tests/prompt-replay.mdx +5 -1
  66. package/docs/snippets/tests/prompt-yaml.mdx +1 -1
  67. package/docs/snippets/tests/remember-replay.mdx +5 -1
  68. package/docs/snippets/tests/scroll-replay.mdx +5 -1
  69. package/docs/snippets/tests/scroll-until-text-replay.mdx +5 -1
  70. package/docs/snippets/tests/type-repeated-replay.mdx +5 -1
  71. package/docs/snippets/tests/type-replay.mdx +5 -1
  72. package/docs/snippets/yml-warning.mdx +4 -1
  73. package/docs/styles.css +6 -0
  74. package/interfaces/logger.js +1 -19
  75. package/package.json +6 -2
  76. package/styles/Microsoft/HeadingAcronyms.yml +1 -1
  77. package/styles/Microsoft/Headings.yml +1 -1
  78. package/styles/Microsoft/Quotes.yml +1 -1
  79. package/styles/Microsoft/Semicolon.yml +1 -1
  80. package/styles/Microsoft/SentenceLength.yml +0 -1
  81. package/styles/Microsoft/Spacing.yml +2 -2
  82. package/styles/Microsoft/Units.yml +4 -4
  83. package/styles/Microsoft/Vocab.yml +1 -1
  84. package/styles/alex/Ablist.yml +58 -29
  85. package/styles/alex/Gendered.yml +4 -2
  86. package/styles/alex/Press.yml +2 -1
  87. package/styles/alex/ProfanityLikely.yml +1284 -1284
  88. package/styles/alex/ProfanityMaybe.yml +1 -1
  89. package/styles/alex/ProfanityUnlikely.yml +1 -1
  90. package/styles/alex/Race.yml +4 -2
  91. package/styles/alex/Suicide.yml +4 -2
  92. package/styles/alex/meta.json +1 -1
  93. package/styles/proselint/AnimalLabels.yml +39 -39
  94. package/styles/proselint/DenizenLabels.yml +44 -44
  95. package/styles/proselint/GenderBias.yml +37 -37
  96. package/styles/proselint/GroupTerms.yml +31 -31
  97. package/styles/proselint/Hedging.yml +1 -1
  98. package/styles/proselint/Hyperbole.yml +1 -1
  99. package/styles/proselint/LGBTTerms.yml +8 -8
  100. package/styles/proselint/Needless.yml +5 -5
  101. package/styles/proselint/RASSyndrome.yml +3 -3
  102. package/styles/proselint/Typography.yml +1 -1
  103. package/styles/proselint/Uncomparables.yml +5 -5
  104. package/styles/proselint/meta.json +1 -3
  105. package/testdriver/acceptance/remember.yaml +1 -1
  106. package/testdriver/behavior/secrets.yaml +7 -0
  107. /package/{upload-docs-to-openai.js → docs/_scripts/upload-docs-to-openai.js} +0 -0
package/agent/events.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const { EventEmitter2 } = require("eventemitter2");
2
+ const { censorSensitiveDataDeep } = require("./lib/censorship");
2
3
 
3
- // Factory function to create a new emitter instance
4
+ // Factory function to create a new emitter instance with censoring middleware
4
5
  const createEmitter = () => {
5
6
  const emitter = new EventEmitter2({
6
7
  wildcard: true,
@@ -11,6 +12,15 @@ const createEmitter = () => {
11
12
  verboseMemoryLeak: false,
12
13
  ignoreErrors: false,
13
14
  });
15
+
16
+ // Override emit to censor sensitive data before emitting
17
+ const originalEmit = emitter.emit.bind(emitter);
18
+ emitter.emit = function (event, ...args) {
19
+ // Censor all arguments passed to emit
20
+ const censoredArgs = args.map(censorSensitiveDataDeep);
21
+ return originalEmit(event, ...censoredArgs);
22
+ };
23
+
14
24
  return emitter;
15
25
  };
16
26
 
package/agent/index.js CHANGED
@@ -1392,7 +1392,7 @@ ${regression}
1392
1392
  const mtime = new Date(stats.mtime);
1393
1393
  const now = new Date();
1394
1394
  const diffMinutes = (now - mtime) / (1000 * 60);
1395
- if (diffMinutes < 30) {
1395
+ if (diffMinutes < 10) {
1396
1396
  const fileContent = fs.readFileSync(lastSandboxFile, "utf-8").trim();
1397
1397
 
1398
1398
  // Parse sandbox info (supports both old format and new format)
@@ -1465,8 +1465,8 @@ ${regression}
1465
1465
  // If instance already exists, do not build environment again
1466
1466
  if (this.instance) {
1467
1467
  this.emitter.emit(
1468
- events.log.log,
1469
- theme.dim("- sandbox instance already exists, skipping launch."),
1468
+ events.log.narration,
1469
+ theme.dim("sandbox instance already exists, skipping launch."),
1470
1470
  );
1471
1471
  return;
1472
1472
  }
@@ -1490,7 +1490,7 @@ ${regression}
1490
1490
  if (!this.config.CI) {
1491
1491
  this.emitter.emit(
1492
1492
  events.log.log,
1493
- theme.dim("-- `new` flag detected, will create a new sandbox"),
1493
+ theme.dim("--`new` flag detected, will create a new sandbox"),
1494
1494
  );
1495
1495
  }
1496
1496
  }
@@ -1503,14 +1503,14 @@ ${regression}
1503
1503
  // Set sandbox ID for reconnection (only if not creating new and recent ID exists)
1504
1504
  if (!createNew && recentId) {
1505
1505
  this.emitter.emit(
1506
- events.log.log,
1507
- theme.dim(`- using recent sandbox: ${recentId}`),
1506
+ events.log.narration,
1507
+ theme.dim(`using recent sandbox: ${recentId}`),
1508
1508
  );
1509
1509
  this.sandboxId = recentId;
1510
1510
  } else if (!createNew) {
1511
1511
  this.emitter.emit(
1512
- events.log.log,
1513
- theme.dim(`- no recent sandbox found, creating a new one.`),
1512
+ events.log.narration,
1513
+ theme.dim(`no recent sandbox found, creating a new one.`),
1514
1514
  );
1515
1515
  }
1516
1516
 
@@ -1543,11 +1543,7 @@ ${regression}
1543
1543
 
1544
1544
  this.emitter.emit(
1545
1545
  events.log.narration,
1546
- theme.dim(`creating new sandbox...`),
1547
- );
1548
- this.emitter.emit(
1549
- events.log.log,
1550
- theme.dim(`this can take between 10 - 240 seconds`),
1546
+ theme.dim(`creating new sandbox (can take up to 2 minutes)...`),
1551
1547
  );
1552
1548
  // We don't have resiliency/retries baked in, so let's at least give it 1 attempt
1553
1549
  // to see if that fixes the issue.
@@ -0,0 +1,70 @@
1
+ // Shared censorship functionality for sensitive data
2
+ // Uses @npmcli/redact for common patterns (URLs, auth headers, etc.)
3
+ // Plus custom logic for environment variables and interpolation vars
4
+ const { redactLog } = require("@npmcli/redact");
5
+
6
+ let interpolationVars = JSON.parse(process.env.TD_INTERPOLATION_VARS || "{}");
7
+
8
+ // Handle local `TD_*` variables
9
+ for (const [key, value] of Object.entries(process.env)) {
10
+ if (key.startsWith("TD_") && key !== "TD_INTERPOLATION_VARS") {
11
+ interpolationVars[key] = value;
12
+ }
13
+ }
14
+
15
+ // Function to censor sensitive data in strings using both npmcli/redact and custom logic
16
+ const censorSensitiveData = (message) => {
17
+ if (typeof message !== "string") {
18
+ return message;
19
+ }
20
+
21
+ // First, use npmcli/redact for common patterns:
22
+ // - URLs with credentials (https://user:pass@host)
23
+ // - Authorization headers
24
+ // - Common secret patterns in logs
25
+ let result = redactLog(message);
26
+
27
+ // Then apply our custom interpolation variable redaction
28
+ // This catches application-specific secrets from TD_* env vars
29
+ for (let value of Object.values(interpolationVars)) {
30
+ // Avoid replacing vars that are 0 or 1 characters
31
+ if (value && value.length >= 2) {
32
+ result = result.replaceAll(value, "****");
33
+ }
34
+ }
35
+
36
+ return result;
37
+ };
38
+
39
+ // Function to censor sensitive data in any value (recursive for objects/arrays)
40
+ const censorSensitiveDataDeep = (value) => {
41
+ if (typeof value === "string") {
42
+ return censorSensitiveData(value);
43
+ } else if (Array.isArray(value)) {
44
+ return value.map(censorSensitiveDataDeep);
45
+ } else if (value && typeof value === "object") {
46
+ const result = {};
47
+ for (const [key, val] of Object.entries(value)) {
48
+ result[key] = censorSensitiveDataDeep(val);
49
+ }
50
+ return result;
51
+ }
52
+ return value;
53
+ };
54
+
55
+ // Function to update interpolation variables (for runtime updates)
56
+ const updateInterpolationVars = (newVars) => {
57
+ interpolationVars = { ...interpolationVars, ...newVars };
58
+ };
59
+
60
+ // Function to get current interpolation variables (for debugging)
61
+ const getInterpolationVars = () => {
62
+ return { ...interpolationVars };
63
+ };
64
+
65
+ module.exports = {
66
+ censorSensitiveData,
67
+ censorSensitiveDataDeep,
68
+ updateInterpolationVars,
69
+ getInterpolationVars,
70
+ };
@@ -670,6 +670,8 @@
670
670
  // Handle window resize to recalculate scale (throttled)
671
671
  window.addEventListener("resize", throttle(resizeOverlay, 100));
672
672
 
673
+ setInterval(resizeOverlay, 1000);
674
+
673
675
  // Handle window blur/focus for screen locking
674
676
  window.addEventListener("blur", () => {
675
677
  showInteractionOverlay();
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+
6
+ /**
7
+ * Script to replace command references in Mintlify docs with proper links
8
+ *
9
+ * This script finds instances of command names like `hover-text`, `wait-for-text`, etc.
10
+ * and replaces them with proper Mintlify links to their documentation pages.
11
+ */
12
+
13
+ // Get all command files from the commands directory
14
+ function getCommandNames() {
15
+ const commandsDir = path.join(__dirname, "../", "commands");
16
+
17
+ if (!fs.existsSync(commandsDir)) {
18
+ console.error("Commands directory not found:", commandsDir);
19
+ process.exit(1);
20
+ }
21
+
22
+ const files = fs.readdirSync(commandsDir);
23
+ const commands = files
24
+ .filter((file) => file.endsWith(".mdx"))
25
+ .map((file) => file.replace(".mdx", ""));
26
+
27
+ console.log("Found commands:", commands);
28
+ return commands;
29
+ }
30
+
31
+ // Process a single file
32
+ function processFile(filePath, commands) {
33
+ const content = fs.readFileSync(filePath, "utf-8");
34
+ let modified = content;
35
+ let changes = 0;
36
+
37
+ commands.forEach((command) => {
38
+ // Create regex pattern to match `command-name` but not already linked commands
39
+ // This pattern looks for backtick-wrapped command names that are NOT:
40
+ // 1. Already inside a link: [` or preceded by ]( or ](/
41
+ // 2. Part of an existing link structure
42
+ const pattern = new RegExp(
43
+ `(?<!\\[)\`(${command.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")})\`(?!\\]\\(|\\)\\]|\\]\\(/commands/)`,
44
+ "g",
45
+ );
46
+
47
+ const replacement = `[\`$1\`](/commands/$1)`;
48
+ const newContent = modified.replace(pattern, replacement);
49
+
50
+ if (newContent !== modified) {
51
+ const matchCount = (modified.match(pattern) || []).length;
52
+ console.log(` - Replaced ${matchCount} instances of \`${command}\``);
53
+ changes += matchCount;
54
+ modified = newContent;
55
+ }
56
+ });
57
+
58
+ return { content: modified, changes };
59
+ }
60
+
61
+ // Process all .mdx files in a directory recursively
62
+ function processDirectory(dirPath, commands, exclude = []) {
63
+ const items = fs.readdirSync(dirPath);
64
+ let totalChanges = 0;
65
+
66
+ items.forEach((item) => {
67
+ const itemPath = path.join(dirPath, item);
68
+ const relativePath = path.relative(process.cwd(), itemPath);
69
+
70
+ // Skip excluded directories
71
+ if (exclude.some((ex) => relativePath.includes(ex))) {
72
+ return;
73
+ }
74
+
75
+ const stat = fs.statSync(itemPath);
76
+
77
+ if (stat.isDirectory()) {
78
+ totalChanges += processDirectory(itemPath, commands, exclude);
79
+ } else if (item.endsWith(".mdx")) {
80
+ console.log(`Processing: ${relativePath}`);
81
+ const result = processFile(itemPath, commands);
82
+
83
+ if (result.changes > 0) {
84
+ fs.writeFileSync(itemPath, result.content, "utf-8");
85
+ console.log(` ✅ Updated with ${result.changes} changes`);
86
+ totalChanges += result.changes;
87
+ } else {
88
+ console.log(` ⏭️ No changes needed`);
89
+ }
90
+ }
91
+ });
92
+
93
+ return totalChanges;
94
+ }
95
+
96
+ // Main function
97
+ function main() {
98
+ console.log("🚀 Starting TestDriver AI docs link replacer...\n");
99
+
100
+ // Get command names from the commands directory
101
+ const commands = getCommandNames();
102
+
103
+ if (commands.length === 0) {
104
+ console.log("No commands found. Exiting.");
105
+ return;
106
+ }
107
+
108
+ console.log(`\n📝 Processing documentation files...\n`);
109
+
110
+ // Process all .mdx files in the docs directory, excluding the commands directory itself
111
+ const docsDir = path.join(__dirname, "../");
112
+ const exclude = ["commands"]; // Don't modify the command docs themselves
113
+
114
+ const totalChanges = processDirectory(docsDir, commands, exclude);
115
+
116
+ console.log(`\n✨ Complete! Made ${totalChanges} total replacements.`);
117
+
118
+ if (totalChanges > 0) {
119
+ console.log("\n📋 Summary:");
120
+ console.log(
121
+ "- Command references like `hover-text` have been replaced with [`hover-text`](/commands/hover-text)",
122
+ );
123
+ console.log("- Only changed files that needed updates");
124
+ console.log(
125
+ "- Excluded the /commands directory to avoid self-referencing issues",
126
+ );
127
+ console.log("\nYou may want to review the changes before committing.");
128
+ } else {
129
+ console.log("\n🎉 All files are already properly linked!");
130
+ }
131
+ }
132
+
133
+ // Handle command line arguments
134
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
135
+ console.log(`
136
+ TestDriver AI Documentation Link Replacer
137
+
138
+ Usage: node link-replacer.js [options]
139
+
140
+ Options:
141
+ --help, -h Show this help message
142
+ --dry-run Show what would be changed without making actual changes (TODO)
143
+
144
+ Description:
145
+ This script finds command references like \`hover-text\` in your Mintlify
146
+ documentation and replaces them with proper links to the command reference
147
+ pages like [\`hover-text\`](/commands/hover-text).
148
+
149
+ The script:
150
+ - Scans all .mdx files in the /docs directory
151
+ - Excludes the /commands directory to avoid self-references
152
+ - Only replaces \`command-name\` patterns that aren't already linked
153
+ - Preserves existing links and formatting
154
+ `);
155
+ process.exit(0);
156
+ }
157
+
158
+ // Run the script
159
+ try {
160
+ main();
161
+ } catch (error) {
162
+ console.error("❌ Error:", error.message);
163
+ process.exit(1);
164
+ }
@@ -4,10 +4,13 @@ sidebarTitle: "Dashboard"
4
4
  description: "Explore your TestDriver dashboard and its features."
5
5
  icon: "gauge"
6
6
  ---
7
+
7
8
  ## Welcome to your TestDriver dashboard
9
+
8
10
  Your dashboard is your command center for managing your TestDriver experience. Here, you can view your projects, monitor usage, and access various features to enhance your testing workflow.
9
11
 
10
12
  ## Key features
13
+
11
14
  - **Projects**: Get a quick snapshot of your projects, with all Dashcam replays.
12
- - **Team**: Manage your API key, and add/remove team members.
13
- - **Usage & Billing**: Monitor your usage and credits in real-time.
15
+ - **Team**: Manage your API key, and add/remove team members.
16
+ - **Usage & Billing**: Monitor your usage and credits in real-time.
@@ -6,6 +6,7 @@ icon: "dollar-sign"
6
6
  ---
7
7
 
8
8
  ## TestDriver pricing plans
9
+
9
10
  TestDriver offers a range of pricing plans to suit different needs, from individual developers to large enterprises. Our plans are designed to provide flexibility and scalability, ensuring you can choose the right option for your testing requirements.
10
11
 
11
12
  <CardGroup cols={3}>
@@ -13,14 +14,20 @@ TestDriver offers a range of pricing plans to suit different needs, from individ
13
14
  Local agent testing. Always free.
14
15
  </Card>
15
16
  <Card title="Pro" icon="briefcase">
16
- Use local or hosted runners on demand or integrated with CI for as low as $0.05/minute.
17
+ Use local or hosted runners on demand or integrated with CI for as low as
18
+ $0.05/minute.
17
19
  </Card>
18
- <Card title="Enterprise" icon="shield">
19
- Need advanced features? Contact us for tailored solutions. Starting at $995/month.
20
+ <Card title="Enterprise" icon="shield">
21
+ Need advanced features? Contact us for tailored solutions. Starting at
22
+ $995/month.
20
23
  </Card>
21
24
  </CardGroup>
22
25
 
23
- <Tip>Every plan starts with $100 in TestDriver credits to get you off the starting line!</Tip>
26
+ <Tip>
27
+ Every plan starts with $100 in TestDriver credits to get you off the starting
28
+ line!
29
+ </Tip>
24
30
 
25
31
  ## Compare plans
26
- To view the latest pricing and features, please visit our [Pricing Page](https://testdriver.ai/pricing).
32
+
33
+ To view the latest pricing and features, please visit our [Pricing Page](https://testdriver.ai/pricing).
@@ -6,6 +6,7 @@ icon: "folder"
6
6
  ---
7
7
 
8
8
  ## Dashboard project view
9
+
9
10
  In the Project tab, select a Project to see the replays for that project.
10
11
 
11
12
  <Frame caption="Click a Project to view its replays">
@@ -18,10 +19,10 @@ From the Project view, you can see all the replays (Dashes) stored for that proj
18
19
  <img src="/images/content/account/projectreplays.png" />
19
20
  </Frame>
20
21
 
21
-
22
22
  ## New project
23
+
23
24
  When you create a new Project, you can also enable the <Icon icon="jira" /> Jira integration to create issues automatically each time a replay (Dash) is created.
24
25
 
25
26
  <Frame caption="Click a Project to view its replays">
26
27
  <img src="/images/content/account/newprojectsettings.png" />
27
- </Frame>
28
+ </Frame>
@@ -6,9 +6,11 @@ icon: "users"
6
6
  ---
7
7
 
8
8
  ## Important settings in one place
9
+
9
10
  In the Team tab, you can manage your team name, team members, API key, and subscription.
10
11
 
11
12
  ### Let's take a look at the team settings.
13
+
12
14
  <Frame caption="Team Settings">
13
15
  <img src="/images/content/account/teampage.png" />
14
16
  </Frame>
@@ -16,16 +18,18 @@ In the Team tab, you can manage your team name, team members, API key, and subsc
16
18
  1. **Team Name**: The name of your team. This is used to identify your team in TestDriver.
17
19
  2. **API Key**: Your API key is used to authenticate your requests to the TestDriver API. You can regenerate it if you suspect it has been compromised.
18
20
  3. **Usage & Billing**: Monitor your usage and billing information. This includes your current plan, usage limits, and billing history.
19
- <Tip>Note: this button is where you 'Upgrade to Pro' to start your free trial.</Tip>
21
+ <Tip>
22
+ Note: this button is where you 'Upgrade to Pro' to start your free trial.
23
+ </Tip>
20
24
  4. **Replay Visibility**: Toggle whether your replays are public or private by default. This defaults to **private**.
21
25
  5. **Don't forget to save your changes!**: After making any changes, be sure to click the **Update** button to apply them.
22
26
 
23
-
24
27
  ### Team members
28
+
25
29
  <Frame caption="Team Members">
26
30
  <img src="/images/content/account/team-manage.png" />
27
31
  </Frame>
28
32
 
29
33
  1. **Email Invite**: Invite new team members by entering their email address and clicking the **Invite** button. They will receive an email invitation to join your team. You can also copy the link above this option to send to everyone at once.
30
34
  2. **Removing Team Members**: To remove a team member, click the **Remove** button next to their name. This will revoke their access to your TestDriver account.
31
- 3. **Invite Status**: The status of the invite will be shown here. If it says **Invited**, the invite hasn't been accepted yet. To resend it, click here.
35
+ 3. **Invite Status**: The status of the invite will be shown here. If it says **Invited**, the invite hasn't been accepted yet. To resend it, click here.
@@ -5,7 +5,7 @@ description: "Test Chrome extensions with TestDriver"
5
5
  icon: "puzzle-piece"
6
6
  ---
7
7
 
8
- import TestPrereqs from '/snippets/test-prereqs.mdx'
8
+ import TestPrereqs from "/snippets/test-prereqs.mdx";
9
9
 
10
10
  <iframe
11
11
  width="600"
@@ -18,16 +18,21 @@ import TestPrereqs from '/snippets/test-prereqs.mdx'
18
18
  ></iframe>
19
19
 
20
20
  # Testing Chrome extensions with TestDriver
21
+
21
22
  TestDriver can be used to test Chrome extensions. This guide provides an overview of how to set up and run tests for your Chrome extension using TestDriver.
22
23
 
23
24
  <TestPrereqs />
24
25
 
25
26
  ## How do I test Chrome extensions?
27
+
26
28
  TestDriver provides a powerful solution for testing Chrome extensions. With our platform, you can easily create and run tests to ensure your extension functions as expected across different browsers and operating systems.
29
+
27
30
  ## Getting started
31
+
28
32
  You can test a preinstalled extension or test by installing an extension. If the extension is in development mode, turn this on by checking the "Developer mode" checkbox in the Chrome extensions page. From there you can load the unpacked extension by selecting the folder where your extension is located. To download the files onto the VM if you are performing a test on cloud hosted runners, see the [Lifecycle](/guide/lifecycle-prerun) and [Prerun](/action/pre-post-scripts) docs.
29
33
 
30
34
  ## Sample test steps
35
+
31
36
  1. Load a the Chrome Web Store.
32
37
  2. Search for the extension you want to test.
33
38
  3. Click on the extension to open its details page.
@@ -39,4 +44,5 @@ You can test a preinstalled extension or test by installing an extension. If the
39
44
  ---
40
45
 
41
46
  ## Now what?
42
- Once you have installed your extension, simply create a TestDriver test to test any functionality a user would use.
47
+
48
+ Once you have installed your extension, simply create a TestDriver test to test any functionality a user would use.
@@ -24,11 +24,11 @@ TestDriver is designed to work with any desktop application, including Electron,
24
24
 
25
25
  ## Sample test steps
26
26
 
27
- 1. **Launch the application**: Use the `exec` command to launch the application. You can specify the path to the executable file and any command-line arguments needed to start the application.
28
- 2. **Wait for the application to load**: Use the `wait-for-text` command to wait for a specific text or element to appear in the application window. This ensures that the application is fully loaded before proceeding with the test.
29
- 3. **Interact with the application**: Use the `focus-application` command to bring the application window to the foreground. Then, use the `hover-image` command to interact with specific elements in the application, such as buttons or text fields.
30
- 4. **Perform actions**: Use the `hover-image` command to click on buttons or enter text in input fields. You can also use the `wait-for-text` command to verify that the expected output appears after performing an action.
31
- 5. **Verify results**: Use the `assert` command to check if the expected result matches the actual output. This step is crucial for validating the functionality of the application.
27
+ 1. **Launch the application**: Use the [`exec`](/commands/exec) command to launch the application. You can specify the path to the executable file and any command-line arguments needed to start the application.
28
+ 2. **Wait for the application to load**: Use the [`wait-for-text`](/commands/wait-for-text) command to wait for a specific text or element to appear in the application window. This ensures that the application is fully loaded before proceeding with the test.
29
+ 3. **Interact with the application**: Use the [`focus-application`](/commands/focus-application) command to bring the application window to the foreground. Then, use the [`hover-image`](/commands/hover-image) command to interact with specific elements in the application, such as buttons or text fields.
30
+ 4. **Perform actions**: Use the [`hover-image`](/commands/hover-image) command to click on buttons or enter text in input fields. You can also use the [`wait-for-text`](/commands/wait-for-text) command to verify that the expected output appears after performing an action.
31
+ 5. **Verify results**: Use the [`assert`](/commands/assert) command to check if the expected result matches the actual output. This step is crucial for validating the functionality of the application.
32
32
 
33
33
  ## Supported desktop applications
34
34
 
@@ -8,14 +8,19 @@ icon: "mobile"
8
8
  # Testing mobile apps with TestDriver
9
9
 
10
10
  ## How do I test mobile apps?
11
+
11
12
  TestDriver provides a powerful solution for testing mobile apps. With our platform, you can easily create and run tests to ensure your mobile app functions as expected across different devices and operating systems.
12
13
 
13
- <Tip>You will need to install a mobile emulator for your deployed tests or use a device farm to test your mobile app.</Tip>
14
+ <Tip>
15
+ You will need to install a mobile emulator for your deployed tests or use a
16
+ device farm to test your mobile app.
17
+ </Tip>
14
18
 
15
19
  ## Gettins started
20
+
16
21
  To get started with testing mobile apps using TestDriver, follow these steps:
22
+
17
23
  1. **Follow our [quick start guide](/overview/quickstart) to set up your TestDriver account.**
18
24
  2. **Create a new test project** in your TestDriver dashboard.
19
25
  3. **Add your mobile emulator to the test settings.**
20
26
  4. **Add your mobile app URL** to the test settings.
21
-
@@ -15,11 +15,11 @@ npx testdriverai@latest <command> [options]
15
15
 
16
16
  ## Available commands
17
17
 
18
- | Command | Description |
19
- | ------- | ------------------------------------------------------------ |
20
- | `run` | Executes a TestDriver test. |
21
- | `edit` | Launch interactive mode. |
22
- | `help` | Displays help information for the CLI or a specific command. |
18
+ | Command | Description |
19
+ | ---------------------- | ------------------------------------------------------------ |
20
+ | [`run`](/commands/run) | Executes a TestDriver test. |
21
+ | `edit` | Launch interactive mode. |
22
+ | `help` | Displays help information for the CLI or a specific command. |
23
23
 
24
24
  ## Available Flags
25
25
 
@@ -63,4 +63,4 @@ npx testdriverai@latest help <command>
63
63
 
64
64
  ## Protips
65
65
 
66
- - Combine `run` and `--headless` with CI/CD pipelines to automate test execution.
66
+ - Combine [`run`](/commands/run) and `--headless` with CI/CD pipelines to automate test execution.
@@ -6,20 +6,22 @@ icon: "check"
6
6
  mode: "wide"
7
7
  ---
8
8
 
9
- import Replay from '/snippets/tests/assert-replay.mdx'
10
- import Example from '/snippets/tests/assert-yaml.mdx'
9
+ import Replay from "/snippets/tests/assert-replay.mdx";
10
+ import Example from "/snippets/tests/assert-yaml.mdx";
11
11
 
12
12
  <Replay />
13
13
  <Example />
14
14
 
15
15
  ## Description
16
+
16
17
  The `assert` command validates that a specific condition is true. It ensures that a task completed successfully by checking the screen for the expected outcome. If the condition isn't met, the test will fail.
17
18
 
18
19
  ## Arguments
19
- | Argument | Type | Description |
20
- |------------|-----------|-----------------------------------------------------------------------------|
21
- | `expect` | `string` | The condition to check. This should describe what you expect to see on the screen. |
22
- | `async` | `boolean` | (Optional) If set to `true`, the test will continue without waiting for the assertion to pass. Default is `false`. |
20
+
21
+ | Argument | Type | Description |
22
+ | -------- | --------- | ------------------------------------------------------------------------------------------------------------------ |
23
+ | `expect` | `string` | The condition to check. This should describe what you expect to see on the screen. |
24
+ | `async` | `boolean` | (Optional) If set to `true`, the test will continue without waiting for the assertion to pass. Default is `false`. |
23
25
 
24
26
  ## Example usage
25
27
 
@@ -37,5 +39,6 @@ async: true
37
39
  ```
38
40
 
39
41
  ## Notes
42
+
40
43
  - Use `async: true` to speed up tests by allowing non-blocking assertions. However, the test will still fail if the condition isn't met.
41
44
  - Ensure the `expect` string clearly describes the condition to avoid ambiguity.
@@ -6,8 +6,8 @@ icon: "image"
6
6
  mode: "wide"
7
7
  ---
8
8
 
9
- import Replay from '/snippets/tests/hover-image-replay.mdx'
10
- import Example from '/snippets/tests/hover-image-yaml.mdx'
9
+ import Replay from "/snippets/tests/hover-image-replay.mdx";
10
+ import Example from "/snippets/tests/hover-image-yaml.mdx";
11
11
 
12
12
  <Replay />
13
13
  <Example />
@@ -17,14 +17,16 @@ import Example from '/snippets/tests/hover-image-yaml.mdx'
17
17
  The `hover-image` command is used to locate an image on the screen based on a description and perform an action on it. This can include hovering, clicking, right-clicking, or double-clicking the image.
18
18
 
19
19
  ## Arguments
20
- | Argument | Type | Description |
21
- |---------------|----------|-----------------------------------------------------------------------------|
22
- | `description` | `string` | A description of the image and what it represents. Don't include the image itself here. |
20
+
21
+ | Argument | Type | Description |
22
+ | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
23
+ | `description` | `string` | A description of the image and what it represents. Don't include the image itself here. |
23
24
  | `action` | `string` | The action to take when the image is found. Available actions are: `click`, `right-click`, `double-click`, `hover`. |
24
25
 
25
26
  The `hover-image` command is useful for interacting with visual elements that can't be identified using text-based selectors.
26
27
 
27
28
  ## Example usage
29
+
28
30
  ```yaml
29
31
  command: hover-image
30
32
  description: search icon in the webpage content
@@ -32,11 +34,12 @@ action: click
32
34
  ```
33
35
 
34
36
  ## Protips
37
+
35
38
  - Use clear and concise descriptions for the image to improve detection accuracy.
36
39
  - Ensure the action specified matches the intended interaction with the image.
37
40
  - If the hover-image command fails to locate an image based on the provided description, consider using the match-image command instead. The match-image command is specifically designed for scenarios where precise image matching is required, such as when the visual element can't be reliably described with text. It works by directly comparing the image on the screen with a reference image file.
38
41
 
39
42
  ## Gotchas
43
+
40
44
  - If the image can't be located based on the description, the command will fail.
41
45
  - Ensure the screen resolution and scaling settings are consistent to avoid detection issues.
42
-