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.
- package/agent/events.js +11 -1
- package/agent/index.js +9 -13
- package/agent/lib/censorship.js +70 -0
- package/debugger/index.html +2 -0
- package/docs/_scripts/link-replacer.js +164 -0
- package/docs/account/dashboard.mdx +5 -2
- package/docs/account/pricing.mdx +12 -5
- package/docs/account/projects.mdx +3 -2
- package/docs/account/team.mdx +7 -3
- package/docs/apps/chrome-extensions.mdx +8 -2
- package/docs/apps/desktop-apps.mdx +5 -5
- package/docs/apps/mobile-apps.mdx +7 -2
- package/docs/cli/overview.mdx +6 -6
- package/docs/commands/assert.mdx +9 -6
- package/docs/commands/hover-image.mdx +9 -6
- package/docs/commands/if.mdx +11 -6
- package/docs/commands/match-image.mdx +13 -6
- package/docs/commands/remember.mdx +10 -5
- package/docs/commands/run.mdx +8 -2
- package/docs/commands/type.mdx +11 -5
- package/docs/commands/wait-for-image.mdx +9 -3
- package/docs/commands/wait.mdx +9 -4
- package/docs/features/generation.mdx +1 -1
- package/docs/features/reusable-snippets.mdx +8 -5
- package/docs/features/selectorless.mdx +13 -6
- package/docs/features/visual-assertions.mdx +53 -39
- package/docs/getting-started/editing.mdx +1 -1
- package/docs/guide/assertions.mdx +12 -17
- package/docs/guide/code.mdx +2 -2
- package/docs/guide/lifecycle.mdx +3 -3
- package/docs/guide/locating.mdx +13 -6
- package/docs/guide/waiting.mdx +41 -32
- package/docs/interactive/assert.mdx +11 -0
- package/docs/interactive/generate.mdx +11 -0
- package/docs/interactive/run.mdx +8 -0
- package/docs/interactive/save.mdx +7 -0
- package/docs/interactive/undo.mdx +11 -3
- package/docs/overview/comparison.mdx +50 -49
- package/docs/overview/faq.mdx +40 -2
- package/docs/overview/performance.mdx +25 -25
- package/docs/overview/what-is-testdriver.mdx +24 -22
- package/docs/scenarios/ai-chatbot.mdx +6 -5
- package/docs/scenarios/cookie-banner.mdx +4 -1
- package/docs/scenarios/file-upload.mdx +7 -4
- package/docs/scenarios/form-filling.mdx +4 -1
- package/docs/scenarios/pdf-generation.mdx +5 -2
- package/docs/scenarios/spell-check.mdx +3 -3
- package/docs/security/agent.mdx +14 -2
- package/docs/security/platform.mdx +17 -5
- package/docs/snippets/calendar-link.mdx +4 -1
- package/docs/snippets/comments.mdx +1 -1
- package/docs/snippets/gitignore-warning.mdx +6 -3
- package/docs/snippets/lifecycle-warning.mdx +6 -1
- package/docs/snippets/tests/assert-replay.mdx +5 -1
- package/docs/snippets/tests/exec-js-replay.mdx +5 -1
- package/docs/snippets/tests/exec-shell-replay.mdx +5 -1
- package/docs/snippets/tests/hover-image-replay.mdx +5 -1
- package/docs/snippets/tests/hover-image-yaml.mdx +2 -2
- package/docs/snippets/tests/hover-text-replay.mdx +5 -1
- package/docs/snippets/tests/hover-text-with-description-replay.mdx +5 -2
- package/docs/snippets/tests/hover-text-with-description-yaml.mdx +2 -2
- package/docs/snippets/tests/match-image-replay.mdx +5 -1
- package/docs/snippets/tests/match-image-yaml.mdx +2 -2
- package/docs/snippets/tests/press-keys-replay.mdx +5 -1
- package/docs/snippets/tests/prompt-replay.mdx +5 -1
- package/docs/snippets/tests/prompt-yaml.mdx +1 -1
- package/docs/snippets/tests/remember-replay.mdx +5 -1
- package/docs/snippets/tests/scroll-replay.mdx +5 -1
- package/docs/snippets/tests/scroll-until-text-replay.mdx +5 -1
- package/docs/snippets/tests/type-repeated-replay.mdx +5 -1
- package/docs/snippets/tests/type-replay.mdx +5 -1
- package/docs/snippets/yml-warning.mdx +4 -1
- package/docs/styles.css +6 -0
- package/interfaces/logger.js +1 -19
- package/package.json +6 -2
- package/styles/Microsoft/HeadingAcronyms.yml +1 -1
- package/styles/Microsoft/Headings.yml +1 -1
- package/styles/Microsoft/Quotes.yml +1 -1
- package/styles/Microsoft/Semicolon.yml +1 -1
- package/styles/Microsoft/SentenceLength.yml +0 -1
- package/styles/Microsoft/Spacing.yml +2 -2
- package/styles/Microsoft/Units.yml +4 -4
- package/styles/Microsoft/Vocab.yml +1 -1
- package/styles/alex/Ablist.yml +58 -29
- package/styles/alex/Gendered.yml +4 -2
- package/styles/alex/Press.yml +2 -1
- package/styles/alex/ProfanityLikely.yml +1284 -1284
- package/styles/alex/ProfanityMaybe.yml +1 -1
- package/styles/alex/ProfanityUnlikely.yml +1 -1
- package/styles/alex/Race.yml +4 -2
- package/styles/alex/Suicide.yml +4 -2
- package/styles/alex/meta.json +1 -1
- package/styles/proselint/AnimalLabels.yml +39 -39
- package/styles/proselint/DenizenLabels.yml +44 -44
- package/styles/proselint/GenderBias.yml +37 -37
- package/styles/proselint/GroupTerms.yml +31 -31
- package/styles/proselint/Hedging.yml +1 -1
- package/styles/proselint/Hyperbole.yml +1 -1
- package/styles/proselint/LGBTTerms.yml +8 -8
- package/styles/proselint/Needless.yml +5 -5
- package/styles/proselint/RASSyndrome.yml +3 -3
- package/styles/proselint/Typography.yml +1 -1
- package/styles/proselint/Uncomparables.yml +5 -5
- package/styles/proselint/meta.json +1 -3
- package/testdriver/acceptance/remember.yaml +1 -1
- package/testdriver/behavior/secrets.yaml +7 -0
- /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 <
|
|
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.
|
|
1469
|
-
theme.dim("
|
|
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("
|
|
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.
|
|
1507
|
-
theme.dim(
|
|
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.
|
|
1513
|
-
theme.dim(
|
|
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
|
+
};
|
package/debugger/index.html
CHANGED
|
@@ -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.
|
package/docs/account/pricing.mdx
CHANGED
|
@@ -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
|
|
17
|
+
Use local or hosted runners on demand or integrated with CI for as low as
|
|
18
|
+
$0.05/minute.
|
|
17
19
|
</Card>
|
|
18
|
-
|
|
19
|
-
Need advanced features? Contact us for tailored solutions. Starting at
|
|
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>
|
|
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
|
-
|
|
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>
|
package/docs/account/team.mdx
CHANGED
|
@@ -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>
|
|
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
|
|
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
|
-
|
|
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>
|
|
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
|
-
|
package/docs/cli/overview.mdx
CHANGED
|
@@ -15,11 +15,11 @@ npx testdriverai@latest <command> [options]
|
|
|
15
15
|
|
|
16
16
|
## Available commands
|
|
17
17
|
|
|
18
|
-
| Command
|
|
19
|
-
|
|
|
20
|
-
| `run`
|
|
21
|
-
| `edit`
|
|
22
|
-
| `help`
|
|
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.
|
package/docs/commands/assert.mdx
CHANGED
|
@@ -6,20 +6,22 @@ icon: "check"
|
|
|
6
6
|
mode: "wide"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
import Replay from
|
|
10
|
-
import Example from
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
|
22
|
-
| `
|
|
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
|
|
10
|
-
import Example from
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
|
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
|
-
|