@timetotest/cli 0.1.1
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/README.md +263 -0
- package/dist/bin/ttt.js +30 -0
- package/dist/bin/ttt.js.map +1 -0
- package/dist/src/commands/ask.js +864 -0
- package/dist/src/commands/ask.js.map +1 -0
- package/dist/src/commands/login.js +257 -0
- package/dist/src/commands/login.js.map +1 -0
- package/dist/src/commands/report.js +25 -0
- package/dist/src/commands/report.js.map +1 -0
- package/dist/src/commands/restart.js +17 -0
- package/dist/src/commands/restart.js.map +1 -0
- package/dist/src/commands/share.js +18 -0
- package/dist/src/commands/share.js.map +1 -0
- package/dist/src/commands/start-test.js +97 -0
- package/dist/src/commands/start-test.js.map +1 -0
- package/dist/src/commands/status.js +17 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/commands/stream.js +20 -0
- package/dist/src/commands/stream.js.map +1 -0
- package/dist/src/commands/test.js +129 -0
- package/dist/src/commands/test.js.map +1 -0
- package/dist/src/lib/config.js +120 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/help.js +94 -0
- package/dist/src/lib/help.js.map +1 -0
- package/dist/src/lib/http.js +16 -0
- package/dist/src/lib/http.js.map +1 -0
- package/dist/src/lib/ngrok.js +35 -0
- package/dist/src/lib/ngrok.js.map +1 -0
- package/dist/src/lib/socket.js +16 -0
- package/dist/src/lib/socket.js.map +1 -0
- package/dist/src/lib/tui.js +509 -0
- package/dist/src/lib/tui.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
### Time to Test CLI (`@timetotest/cli`)
|
|
2
|
+
|
|
3
|
+
AI-powered web testing from your terminal. Start tests against your app, stream real-time progress, and download shareable reports.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
1. Log in
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
ttt login
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. Start a test
|
|
14
|
+
|
|
15
|
+
- Easiest (no URL needed, uses your project’s saved URL):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
ttt start-test "Smoke test the main user journey" --execute --wait
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- With an explicit URL:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ttt test --url https://your-app.com --type ui --execute --wait
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. Chat with the agent
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ttt ask
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Tips:
|
|
34
|
+
|
|
35
|
+
- Use `--report [path]` to download a PDF when the test completes
|
|
36
|
+
- Use `--share` to enable a public share link
|
|
37
|
+
- Use `ttt stream <test-id>` to reattach to progress later
|
|
38
|
+
|
|
39
|
+
- **Node requirement**: 18+
|
|
40
|
+
- **Website**: [Time to Test](https://timetotest.tech)
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm i -g @timetotest/cli
|
|
46
|
+
# or use npx without global install
|
|
47
|
+
npx @timetotest/cli --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
1. Authenticate
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
ttt login
|
|
56
|
+
# Opens a browser to authenticate. As a fallback, you may be prompted to paste a short-lived token.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
2. Run a UI test against a local app
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ttt test \
|
|
63
|
+
--url http://localhost:3000 \
|
|
64
|
+
--type ui \
|
|
65
|
+
--execute \
|
|
66
|
+
--mode priority \
|
|
67
|
+
--project-id 123 \
|
|
68
|
+
--team-id 456 \
|
|
69
|
+
--report ./report.pdf \
|
|
70
|
+
--wait
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The CLI will automatically start an ngrok tunnel for local URLs and stream progress via Socket.IO.
|
|
74
|
+
|
|
75
|
+
## Authentication
|
|
76
|
+
|
|
77
|
+
- **Interactive**: `ttt login` opens the browser and stores a Firebase ID token in `~/.timetotest/config.json`.
|
|
78
|
+
- **Headless/CI**: Use Firebase Email/Password (service user):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ttt login --email "$TTT_EMAIL" --password "$TTT_PASSWORD" --api-key "$TTT_FIREBASE_API_KEY"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- **Direct token**: `ttt login --token <FIREBASE_ID_TOKEN>`
|
|
85
|
+
- **Env override**: Set `TTT_TOKEN` to inject the token for one-off runs.
|
|
86
|
+
|
|
87
|
+
## Commands
|
|
88
|
+
|
|
89
|
+
- **ttt login**
|
|
90
|
+
|
|
91
|
+
- Options:
|
|
92
|
+
- `--device` (reserved)
|
|
93
|
+
- `--email <email> --password <password> --api-key <firebase-web-api-key>`
|
|
94
|
+
- `--token <FIREBASE_ID_TOKEN>`
|
|
95
|
+
|
|
96
|
+
- **ttt test**
|
|
97
|
+
|
|
98
|
+
- Starts a test and subscribes to real-time events.
|
|
99
|
+
- Key options:
|
|
100
|
+
- `--url <ui-url>`: app URL under test (required for UI/mixed)
|
|
101
|
+
- `--type <ui|api|mixed>`: defaults to `ui`
|
|
102
|
+
- `--execute`: execute generated test cases
|
|
103
|
+
- `--mode <all|priority|failed_only>`: defaults to `priority`
|
|
104
|
+
- `--project-id <id>` / `--team-id <id>`
|
|
105
|
+
- `--docs-url <openapi-url>`: API docs (OpenAPI/Swagger)
|
|
106
|
+
- `--no-tunnel`: disable auto ngrok tunnel for local URLs
|
|
107
|
+
- `--report [path]`: download PDF on completion (default `./report-<id>.pdf`)
|
|
108
|
+
- `--share`: enable public sharing after completion
|
|
109
|
+
- `--wait`: block until completion and set exit code based on result
|
|
110
|
+
|
|
111
|
+
- **ttt start-test <prompt>**
|
|
112
|
+
|
|
113
|
+
- Start a test from a natural language prompt. The backend derives the URL from your selected/last project, so you don't need to pass `--url`.
|
|
114
|
+
- Examples:
|
|
115
|
+
```bash
|
|
116
|
+
ttt start-test "Smoke test the main user journey and generate a PDF report" --execute --wait
|
|
117
|
+
ttt start-test "API regression for orders endpoints" --type api --docs-url https://api.example.com/openapi.json --execute
|
|
118
|
+
```
|
|
119
|
+
- Options:
|
|
120
|
+
- `--type <ui|api|mixed>`: defaults to `ui`
|
|
121
|
+
- `--execute`: execute generated test cases
|
|
122
|
+
- `--mode <all|priority|failed_only>`: defaults to `priority`
|
|
123
|
+
- `--project-id <id>` / `--team-id <id>`
|
|
124
|
+
- `--docs-url <openapi-url>`: API docs (OpenAPI/Swagger)
|
|
125
|
+
- `--report [path]`: download PDF on completion (default `./report-<id>.pdf`)
|
|
126
|
+
- `--share`: enable public sharing after completion
|
|
127
|
+
- `--wait`: block until completion and set exit code based on result
|
|
128
|
+
|
|
129
|
+
- **ttt stream <test-id>**
|
|
130
|
+
|
|
131
|
+
- Attach to an existing test and print textual progress only.
|
|
132
|
+
|
|
133
|
+
- **ttt status <test-id>**
|
|
134
|
+
|
|
135
|
+
- Print the test status JSON.
|
|
136
|
+
|
|
137
|
+
- **ttt restart <test-id>**
|
|
138
|
+
|
|
139
|
+
- Re-run a completed or failed test.
|
|
140
|
+
|
|
141
|
+
- **ttt report <test-id> --out <file.pdf>**
|
|
142
|
+
|
|
143
|
+
- Create (if needed) and download a PDF report.
|
|
144
|
+
|
|
145
|
+
- **ttt share <test-id>**
|
|
146
|
+
- Enable public sharing and print the public URL.
|
|
147
|
+
|
|
148
|
+
## Real-time Streaming
|
|
149
|
+
|
|
150
|
+
The CLI connects to Socket.IO at `/socket.io` and emits `subscribe_test` with the test ID. It prints minimal, time-stamped lines for events like `test_started`, `test_progress`, `test_completed`, `test_failed`.
|
|
151
|
+
|
|
152
|
+
If websockets are blocked, use `ttt status <id>` to poll.
|
|
153
|
+
|
|
154
|
+
## Tunnels (Local URLs)
|
|
155
|
+
|
|
156
|
+
When `--url` (or `--docs-url`) points to `localhost`/`127.0.0.1`, the CLI auto-starts an ngrok tunnel and injects the public URL into the request. For reliability, provide an ngrok authtoken:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
export TTT_NGROK_AUTHTOKEN=... # optional but recommended
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Configuration
|
|
163
|
+
|
|
164
|
+
- **Precedence**: CLI flags > environment variables > config file.
|
|
165
|
+
- **Config file**: `~/.timetotest/config.json`
|
|
166
|
+
|
|
167
|
+
Example (values are examples; your file will reflect your environment):
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"apiUrl": "https://api.timetotest.tech",
|
|
172
|
+
"socketUrl": "https://api.timetotest.tech",
|
|
173
|
+
"auth": {"firebaseIdToken": "...", "expiresAt": 0},
|
|
174
|
+
"defaultProjectId": null,
|
|
175
|
+
"defaultTeamId": null,
|
|
176
|
+
"ngrok": {"authtoken": null}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Environment Variables
|
|
181
|
+
|
|
182
|
+
- `TTT_API_URL` – override API base URL
|
|
183
|
+
- `TTT_SOCKET_URL` – override Socket.IO base URL
|
|
184
|
+
- `TTT_TOKEN` – Firebase ID token (overrides stored token)
|
|
185
|
+
- `TTT_NGROK_AUTHTOKEN` – ngrok account token
|
|
186
|
+
|
|
187
|
+
## GitHub Actions (Example)
|
|
188
|
+
|
|
189
|
+
```yaml
|
|
190
|
+
name: Time to Test
|
|
191
|
+
on:
|
|
192
|
+
push:
|
|
193
|
+
branches: [main]
|
|
194
|
+
|
|
195
|
+
jobs:
|
|
196
|
+
ttt:
|
|
197
|
+
runs-on: ubuntu-latest
|
|
198
|
+
steps:
|
|
199
|
+
- uses: actions/checkout@v4
|
|
200
|
+
- uses: actions/setup-node@v4
|
|
201
|
+
with:
|
|
202
|
+
node-version: "20"
|
|
203
|
+
|
|
204
|
+
- name: Install CLI
|
|
205
|
+
run: npm i -g @timetotest/cli
|
|
206
|
+
|
|
207
|
+
- name: Start App Under Test
|
|
208
|
+
run: |
|
|
209
|
+
npm ci
|
|
210
|
+
npm run build --if-present
|
|
211
|
+
npm start &
|
|
212
|
+
echo $! > app.pid
|
|
213
|
+
npx wait-on http://localhost:3000
|
|
214
|
+
|
|
215
|
+
- name: CLI Login (headless)
|
|
216
|
+
env:
|
|
217
|
+
TTT_EMAIL: ${{ secrets.TTT_EMAIL }}
|
|
218
|
+
TTT_PASSWORD: ${{ secrets.TTT_PASSWORD }}
|
|
219
|
+
TTT_FIREBASE_API_KEY: ${{ secrets.TTT_FIREBASE_API_KEY }}
|
|
220
|
+
run: ttt login --email "$TTT_EMAIL" --password "$TTT_PASSWORD" --api-key "$TTT_FIREBASE_API_KEY"
|
|
221
|
+
|
|
222
|
+
- name: Run Test
|
|
223
|
+
env:
|
|
224
|
+
TTT_API_URL: https://dev.timetotest.kinra.ng
|
|
225
|
+
TTT_SOCKET_URL: https://dev.timetotest.kinra.ng
|
|
226
|
+
TTT_NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }}
|
|
227
|
+
run: |
|
|
228
|
+
ttt test \
|
|
229
|
+
--url http://localhost:3000 \
|
|
230
|
+
--type ui \
|
|
231
|
+
--execute \
|
|
232
|
+
--mode priority \
|
|
233
|
+
--project-id 123 \
|
|
234
|
+
--team-id 456 \
|
|
235
|
+
--report ./report.pdf \
|
|
236
|
+
--wait
|
|
237
|
+
|
|
238
|
+
- name: Upload Report (PDF)
|
|
239
|
+
uses: actions/upload-artifact@v4
|
|
240
|
+
with:
|
|
241
|
+
name: timetotest-report
|
|
242
|
+
path: ./report.pdf
|
|
243
|
+
|
|
244
|
+
- name: Stop App
|
|
245
|
+
if: always()
|
|
246
|
+
run: kill $(cat app.pid) || true
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Troubleshooting
|
|
250
|
+
|
|
251
|
+
- **401 Unauthorized**: run `ttt login` again or set `TTT_TOKEN`.
|
|
252
|
+
- **Tunnel issues**: set `TTT_NGROK_AUTHTOKEN`, ensure your local app is running and reachable.
|
|
253
|
+
- **Socket blocked**: use `ttt status <id>` for polling.
|
|
254
|
+
- **PDF not saving**: ensure the output path is writable.
|
|
255
|
+
|
|
256
|
+
## Privacy & Security
|
|
257
|
+
|
|
258
|
+
- Your token is stored in `~/.timetotest/config.json` with restricted permissions.
|
|
259
|
+
- The CLI avoids logging secrets; still, prefer not to paste sensitive URLs directly in shared logs.
|
|
260
|
+
|
|
261
|
+
## Feedback
|
|
262
|
+
|
|
263
|
+
We’d love to hear from you. Visit [Time to Test](https://timetotest.tech) for updates and support.
|
package/dist/bin/ttt.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { login } from "../src/commands/login.js";
|
|
4
|
+
import { test } from "../src/commands/test.js";
|
|
5
|
+
import { status } from "../src/commands/status.js";
|
|
6
|
+
import { restart } from "../src/commands/restart.js";
|
|
7
|
+
import { stream } from "../src/commands/stream.js";
|
|
8
|
+
import { report } from "../src/commands/report.js";
|
|
9
|
+
import { share } from "../src/commands/share.js";
|
|
10
|
+
import { ask } from "../src/commands/ask.js";
|
|
11
|
+
import { startTest } from "../src/commands/start-test.js";
|
|
12
|
+
import { applyStyledHelpRecursively } from "../src/lib/help.js";
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program.name("ttt").description("Time to Test CLI").version("0.1.0");
|
|
15
|
+
program.addCommand(login);
|
|
16
|
+
program.addCommand(test);
|
|
17
|
+
program.addCommand(status);
|
|
18
|
+
program.addCommand(restart);
|
|
19
|
+
program.addCommand(stream);
|
|
20
|
+
program.addCommand(report);
|
|
21
|
+
program.addCommand(share);
|
|
22
|
+
program.addCommand(ask);
|
|
23
|
+
program.addCommand(startTest);
|
|
24
|
+
applyStyledHelpRecursively(program, "ttt");
|
|
25
|
+
// Default to `ask` when no subcommand is provided
|
|
26
|
+
if (process.argv.length <= 2) {
|
|
27
|
+
process.argv.push("ask");
|
|
28
|
+
}
|
|
29
|
+
program.parseAsync(process.argv);
|
|
30
|
+
//# sourceMappingURL=ttt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ttt.js","sourceRoot":"","sources":["../../bin/ttt.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,OAAO,EAAC,KAAK,EAAC,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAC,IAAI,EAAC,MAAM,yBAAyB,CAAC;AAC7C,OAAO,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAC,OAAO,EAAC,MAAM,4BAA4B,CAAC;AACnD,OAAO,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAC,MAAM,EAAC,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAC,KAAK,EAAC,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAC,GAAG,EAAC,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAC,SAAS,EAAC,MAAM,+BAA+B,CAAC;AACxD,OAAO,EAAC,0BAA0B,EAAC,MAAM,oBAAoB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAErE,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC1B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACzB,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC3B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC5B,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC3B,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC3B,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC1B,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACxB,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAE9B,0BAA0B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC3C,kDAAkD;AAClD,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AACD,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|