Skip to content

Commit 1d059ce

Browse files
add codeless test methods
1 parent dc5ceed commit 1d059ce

File tree

5 files changed

+267
-0
lines changed

5 files changed

+267
-0
lines changed

README.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ TestingBot provides a cloud-based test infrastructure for automated cross-browse
2424
- [Storage Management](#storage-management)
2525
- [Screenshots](#screenshots)
2626
- [Team Management](#team-management)
27+
- [Codeless Tests](#codeless-tests)
28+
- [CLI Usage](#cli-usage)
29+
- [Installation](#installation-1)
30+
- [Authentication](#authentication)
31+
- [Available Commands](#available-commands)
32+
- [CLI Examples](#cli-examples)
2733
- [Complete Examples](#complete-examples)
2834
- [Testing](#testing)
2935
- [Contributing](#contributing)
@@ -519,6 +525,148 @@ tb.resetCredentials(userId, function(error, result) {});
519525
const result = await tb.resetCredentials(userId);
520526
```
521527

528+
### Codeless Tests
529+
530+
Codeless tests allow you to create automated tests without writing code. These tests can be configured to run on a schedule and include AI-powered test generation.
531+
532+
#### getCodelessTests
533+
Retrieves a list of codeless tests
534+
535+
```javascript
536+
// Callback style
537+
tb.getCodelessTests(offset, limit, function(error, tests) {});
538+
539+
// Async/await style
540+
const tests = await tb.getCodelessTests(0, 10); // offset: 0, limit: 10
541+
```
542+
543+
#### createCodelessTest
544+
Creates a new codeless test
545+
546+
```javascript
547+
const testData = {
548+
name: 'My Codeless Test', // Required: Test name
549+
url: 'https://example.com', // Required: URL to test
550+
cron: '0 0 * * *', // Optional: Cron schedule
551+
screenshot: true, // Optional: Take screenshots
552+
video: false, // Optional: Record video
553+
idletimeout: 60, // Optional: Idle timeout in seconds
554+
screenresolution: '1920x1080', // Optional: Screen resolution
555+
ai_prompt: 'Test the login flow' // Optional: AI test agent prompt
556+
};
557+
558+
// Callback style
559+
tb.createCodelessTest(testData, function(error, result) {});
560+
561+
// Async/await style
562+
const result = await tb.createCodelessTest(testData);
563+
```
564+
565+
#### updateCodelessTest
566+
Updates an existing codeless test
567+
568+
```javascript
569+
const updateData = {
570+
test: {
571+
name: 'Updated Test Name',
572+
cron: '0 12 * * *'
573+
}
574+
};
575+
576+
// Callback style
577+
tb.updateCodelessTest(updateData, testId, function(error, result) {});
578+
579+
// Async/await style
580+
const result = await tb.updateCodelessTest(updateData, testId);
581+
```
582+
583+
#### deleteCodelessTest
584+
Deletes a codeless test
585+
586+
```javascript
587+
// Callback style
588+
tb.deleteCodelessTest(testId, function(error, result) {});
589+
590+
// Async/await style
591+
const result = await tb.deleteCodelessTest(testId);
592+
```
593+
594+
## CLI Usage
595+
596+
The TestingBot API package includes a command-line interface for quick access to API functionality.
597+
598+
### Installation
599+
600+
```bash
601+
# Install globally for CLI access
602+
npm install -g testingbot-api
603+
604+
# Or use npx with local installation
605+
npx testingbot <command>
606+
```
607+
608+
### Authentication
609+
610+
The CLI uses the same authentication methods as the API client:
611+
- Environment variables: `TB_KEY` and `TB_SECRET` or `TESTINGBOT_KEY` and `TESTINGBOT_SECRET`
612+
- Configuration file: `~/.testingbot` with `api_key` and `api_secret`
613+
614+
### Available Commands
615+
616+
```bash
617+
# User management
618+
testingbot user info # Get user information
619+
testingbot user update <json> # Update user information
620+
621+
# Test management
622+
testingbot tests list [offset] [limit] # List tests
623+
testingbot tests get <id> # Get test details
624+
testingbot tests delete <id> # Delete a test
625+
testingbot tests stop <id> # Stop a running test
626+
627+
# Codeless tests (Lab)
628+
testingbot lab list [offset] [limit] # List codeless tests
629+
testingbot lab create <json> # Create a codeless test
630+
testingbot lab update <id> <json> # Update a codeless test
631+
testingbot lab delete <id> # Delete a codeless test
632+
633+
# Browsers and devices
634+
testingbot browsers list [type] # List browsers (type: all|web|mobile|real)
635+
testingbot devices list # List all devices
636+
testingbot devices available # List available devices
637+
638+
# Storage
639+
testingbot storage upload <file> # Upload a file
640+
testingbot storage list [offset] [limit] # List stored files
641+
testingbot storage delete <id> # Delete a stored file
642+
643+
# Help
644+
testingbot --help # Show help
645+
testingbot --version # Show version
646+
```
647+
648+
### CLI Examples
649+
650+
```bash
651+
# Create a codeless test
652+
testingbot lab create '{
653+
"name": "Homepage Test",
654+
"url": "https://example.com",
655+
"cron": "0 0 * * *",
656+
"screenshot": true,
657+
"ai_prompt": "Test the homepage loads correctly"
658+
}'
659+
660+
# List recent tests
661+
testingbot tests list 0 20
662+
663+
# Get browser list
664+
testingbot browsers list web
665+
666+
# Upload a file to storage
667+
testingbot storage upload ./test-app.zip
668+
```
669+
522670
## Complete Examples
523671

524672
### Basic Usage

bin/testingbot

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Commands:
106106
107107
lab Codeless test management
108108
list [offset] [limit] List codeless tests
109+
create <data> Create codeless test (data as JSON)
109110
update <id> <data> Update codeless test
110111
delete <id> Delete codeless test
111112
@@ -381,6 +382,24 @@ const commands = {
381382
checkCredentials();
382383
api.getCodelessTests(parseInt(offset), parseInt(limit), outputResult);
383384
},
385+
create: (data) => {
386+
checkCredentials();
387+
if (!data) {
388+
console.error('Error: Test data required (as JSON string)');
389+
process.exit(1);
390+
}
391+
try {
392+
const parsedData = JSON.parse(data);
393+
if (!parsedData.name || !parsedData.url) {
394+
console.error('Error: Test name and URL are required');
395+
process.exit(1);
396+
}
397+
api.createCodelessTest(parsedData, outputResult);
398+
} catch (e) {
399+
console.error('Error: Invalid JSON data');
400+
process.exit(1);
401+
}
402+
},
384403
update: (id, data) => {
385404
checkCredentials();
386405
if (!id || !data) {

lib/api.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,30 @@ class TestingBot {
246246
}, callback);
247247
}
248248

249+
createCodelessTest (testData, callback) {
250+
if (!testData || !testData.name || !testData.url) {
251+
throw new Error('Test name and URL are required');
252+
}
253+
254+
const data = {};
255+
256+
// Map test properties to the expected format
257+
if (testData.name) data['test[name]'] = testData.name;
258+
if (testData.url) data['test[url]'] = testData.url;
259+
if (testData.cron) data['test[cron]'] = testData.cron;
260+
if (testData.screenshot !== undefined) data['test[screenshot]'] = testData.screenshot;
261+
if (testData.video !== undefined) data['test[video]'] = testData.video;
262+
if (testData.idletimeout) data['test[idletimeout]'] = testData.idletimeout;
263+
if (testData.screenresolution) data['test[screenresolution]'] = testData.screenresolution;
264+
if (testData.ai_prompt) data['test[ai_prompt]'] = testData.ai_prompt;
265+
266+
return this.request({
267+
method: 'POST',
268+
url: '/lab',
269+
data
270+
}, callback);
271+
}
272+
249273
updateCodelessTest (data, testID, callback) {
250274
if (!testID) {
251275
throw new Error('Test ID is required');

test/api_test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,46 @@ describe('TestingBot API Tests', function() {
419419
});
420420
});
421421

422+
it('should create a codeless test', function(done) {
423+
const testData = {
424+
name: 'Test Codeless Test',
425+
url: 'https://example.com',
426+
cron: '31 * * * *',
427+
screenshot: true,
428+
video: false,
429+
ai_prompt: 'Test the login functionality'
430+
};
431+
432+
this.api.createCodelessTest(testData, (err, response) => {
433+
if (err) {
434+
// If we hit rate limits or don't have permission, skip this test
435+
if (err.message && err.message.includes('rate limit')) {
436+
return done();
437+
}
438+
}
439+
assert.strictEqual(err, null, 'Should not have an error creating codeless test');
440+
assert.ok(response, 'Should have a response');
441+
// Clean up if test was created
442+
if (response && response.id) {
443+
this.api.deleteCodelessTest(response.id, () => {
444+
done();
445+
});
446+
} else {
447+
done();
448+
}
449+
});
450+
});
451+
452+
it('should throw error when creating codeless test without required fields', function(done) {
453+
try {
454+
this.api.createCodelessTest({ name: 'Test' }, function() {});
455+
done(new Error('Should have thrown an error'));
456+
} catch (err) {
457+
assert.ok(err.message.includes('Test name and URL are required'), 'Should throw required fields error');
458+
done();
459+
}
460+
});
461+
422462
it('should throw error when updating codeless test without test ID', function(done) {
423463
try {
424464
this.api.updateCodelessTest({ test: { name: 'Test' } }, null, function() {});

test/cli_test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,42 @@ describe('TestingBot CLI Tests', function () {
664664
}
665665
});
666666

667+
it('should error when test data is missing for create', async function () {
668+
try {
669+
await execWithEnv(`${binaryPath} lab create`, {
670+
TB_KEY: process.env.TB_KEY,
671+
TB_SECRET: process.env.TB_SECRET
672+
});
673+
assert.fail('Should have thrown an error');
674+
} catch (error) {
675+
assert(error.stderr.includes('Test data required'));
676+
}
677+
});
678+
679+
it('should error on invalid JSON for create', async function () {
680+
try {
681+
await execWithEnv(`${binaryPath} lab create "invalid json"`, {
682+
TB_KEY: process.env.TB_KEY,
683+
TB_SECRET: process.env.TB_SECRET
684+
});
685+
assert.fail('Should have thrown an error');
686+
} catch (error) {
687+
assert(error.stderr.includes('Invalid JSON'));
688+
}
689+
});
690+
691+
it('should error when required fields are missing for create', async function () {
692+
try {
693+
await execWithEnv(`${binaryPath} lab create '{"name": "test"}'`, {
694+
TB_KEY: process.env.TB_KEY,
695+
TB_SECRET: process.env.TB_SECRET
696+
});
697+
assert.fail('Should have thrown an error');
698+
} catch (error) {
699+
assert(error.stderr.includes('Test name and URL are required'));
700+
}
701+
});
702+
667703
it('should error when test ID is missing for delete', async function () {
668704
try {
669705
await execWithEnv(`${binaryPath} lab delete`, {

0 commit comments

Comments
 (0)