@postmate/cli 0.1.0 โ 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 +148 -1
- package/dist/index.js +11 -4
- package/dist/utils/reportHelper.js +245 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1 +1,148 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ๐ Postmate CLI
|
|
2
|
+
|
|
3
|
+
Run Postmate API collections directly from your terminal.
|
|
4
|
+
|
|
5
|
+
Postmate CLI enables environment-based execution, data-driven testing, JSON reporting, and CI/CD-ready exit codes โ all without a GUI.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ๐ฆ Installation
|
|
10
|
+
|
|
11
|
+
Install globally using npm:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @postmate/cli
|
|
15
|
+
```
|
|
16
|
+
Verify installation:
|
|
17
|
+
```bash
|
|
18
|
+
pmc --version
|
|
19
|
+
```
|
|
20
|
+
๐ Project Structure
|
|
21
|
+
|
|
22
|
+
Postmate CLI works inside a project that contains a .postmate directory.
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
```
|
|
26
|
+
my-project/
|
|
27
|
+
โ
|
|
28
|
+
โโโ .postmate/
|
|
29
|
+
โ โโโ collections/
|
|
30
|
+
โ โโโ environments/
|
|
31
|
+
โ โโโ data/
|
|
32
|
+
โ โโโ reports/
|
|
33
|
+
โ
|
|
34
|
+
โโโ package.json
|
|
35
|
+
```
|
|
36
|
+
You can run the CLI from:
|
|
37
|
+
- Inside .postmate
|
|
38
|
+
- Or from the project root
|
|
39
|
+
|
|
40
|
+
The CLI automatically detects the correct project folder.
|
|
41
|
+
|
|
42
|
+
โถ๏ธ Running a Collection
|
|
43
|
+
|
|
44
|
+
Basic usage:
|
|
45
|
+
```
|
|
46
|
+
pmc run --collection <collectionName> --env <environmentName>
|
|
47
|
+
```
|
|
48
|
+
Example:
|
|
49
|
+
```
|
|
50
|
+
pmc run --collection school --env Dev
|
|
51
|
+
```
|
|
52
|
+
Each row in the data file will execute the collection once.
|
|
53
|
+
|
|
54
|
+
Variables like:
|
|
55
|
+
```
|
|
56
|
+
{{id}}
|
|
57
|
+
{{username}}
|
|
58
|
+
```
|
|
59
|
+
will resolve per row.
|
|
60
|
+
|
|
61
|
+
๐งช Execution Output
|
|
62
|
+
|
|
63
|
+
Example terminal output:
|
|
64
|
+
```
|
|
65
|
+
๐ Running school
|
|
66
|
+
Env: Dev
|
|
67
|
+
Iterations: 1
|
|
68
|
+
Total Requests: 10
|
|
69
|
+
|
|
70
|
+
โ [1] Get Users (200)
|
|
71
|
+
โ [1] Create User (500)
|
|
72
|
+
|
|
73
|
+
Finished in 3s 120ms
|
|
74
|
+
Total Requests: 10
|
|
75
|
+
Report saved: .postmate/reports/school-Dev-2026-02-14T15-32-10.json
|
|
76
|
+
```
|
|
77
|
+
๐ Reports
|
|
78
|
+
|
|
79
|
+
After every run, a JSON report is automatically generated inside:
|
|
80
|
+
```
|
|
81
|
+
.postmate/reports/
|
|
82
|
+
```
|
|
83
|
+
Filename format:
|
|
84
|
+
```
|
|
85
|
+
<collection>-<environment>-<timestamp>.json
|
|
86
|
+
```
|
|
87
|
+
Example:
|
|
88
|
+
```
|
|
89
|
+
school-Dev-2026-02-14T15-32-10.json
|
|
90
|
+
```
|
|
91
|
+
Reports can be:
|
|
92
|
+
- Stored as CI artifacts
|
|
93
|
+
- Parsed for analytics
|
|
94
|
+
- Converted to JUnit
|
|
95
|
+
- Used for dashboards
|
|
96
|
+
|
|
97
|
+
โ Exit Codes (CI Ready)
|
|
98
|
+
Postmate CLI returns:
|
|
99
|
+
- 0 โ All requests successful (HTTP 2xx)
|
|
100
|
+
- 1 โ One or more failures
|
|
101
|
+
|
|
102
|
+
Example:
|
|
103
|
+
```
|
|
104
|
+
pmc run --collection school --env Dev
|
|
105
|
+
echo $?
|
|
106
|
+
```
|
|
107
|
+
This makes it ready for CI/CD pipelines.
|
|
108
|
+
|
|
109
|
+
โ๏ธ Command Reference
|
|
110
|
+
Run Command
|
|
111
|
+
```
|
|
112
|
+
pmc run --collection <name> --env <envName> [--data <dataFile>]
|
|
113
|
+
```
|
|
114
|
+
Options
|
|
115
|
+
```
|
|
116
|
+
| Option | Description |
|
|
117
|
+
| -------------- | -------------------------------- |
|
|
118
|
+
| `--collection` | Collection name |
|
|
119
|
+
| `--env` | Environment name |
|
|
120
|
+
| `--data` | Optional data file for iteration |
|
|
121
|
+
```
|
|
122
|
+
๐ CI Example (GitHub Actions)
|
|
123
|
+
```
|
|
124
|
+
- name: Run API Tests
|
|
125
|
+
run: pmc run --collection school --env QA
|
|
126
|
+
```
|
|
127
|
+
If any request fails, the pipeline fails automatically.
|
|
128
|
+
|
|
129
|
+
๐ก Best Practices
|
|
130
|
+
- Keep base URLs inside environment files
|
|
131
|
+
- Use data files for bulk execution
|
|
132
|
+
- Version control your .postmate directory
|
|
133
|
+
- Store reports as CI artifacts
|
|
134
|
+
- Use clear environment names (Dev, QA, Prod)
|
|
135
|
+
|
|
136
|
+
๐ฅ Why Postmate CLI?
|
|
137
|
+
- Lightweight
|
|
138
|
+
- Deterministic
|
|
139
|
+
- Scriptable
|
|
140
|
+
- CI-friendly
|
|
141
|
+
- No GUI required
|
|
142
|
+
- Built for automation
|
|
143
|
+
|
|
144
|
+
๐ License
|
|
145
|
+
|
|
146
|
+
ISC
|
|
147
|
+
|
|
148
|
+
Made with โค๏ธ using Postmate
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { findPostmateRoot } from './utils/project.js';
|
|
4
4
|
import { CoreContext } from '@postmate/core';
|
|
5
5
|
import { cliLogger } from "./utils/cliLogger.js";
|
|
6
|
+
import { generateHtmlReport } from "./utils/reportHelper.js";
|
|
6
7
|
import fs from "fs";
|
|
7
8
|
import path from "path";
|
|
8
9
|
const program = new Command();
|
|
@@ -83,11 +84,17 @@ const runCommand = program
|
|
|
83
84
|
const timestamp = new Date()
|
|
84
85
|
.toISOString()
|
|
85
86
|
.replace(/:/g, "-");
|
|
86
|
-
const fileName = `${collection}-${env}-${timestamp}
|
|
87
|
-
const
|
|
87
|
+
const fileName = `${collection}-${env}-${timestamp}`;
|
|
88
|
+
const jsonFilePath = path.join(reportsDir, fileName + '.json');
|
|
89
|
+
const htmlFilePath = path.join(reportsDir, fileName + '.html');
|
|
88
90
|
// 3๏ธโฃ Write JSON
|
|
89
|
-
fs.writeFileSync(
|
|
90
|
-
console.log(`Report saved: ${
|
|
91
|
+
fs.writeFileSync(jsonFilePath, JSON.stringify(info.reportJson, null, 2), "utf-8");
|
|
92
|
+
console.log(`Report saved: ${jsonFilePath}`);
|
|
93
|
+
//generate html report
|
|
94
|
+
const htmlReport = generateHtmlReport(info.reportJson, "Collection Name");
|
|
95
|
+
// 3๏ธโฃ Write JSON
|
|
96
|
+
fs.writeFileSync(htmlFilePath, htmlReport, "utf-8");
|
|
97
|
+
console.log(`HTML Report saved: ${htmlFilePath}`);
|
|
91
98
|
},
|
|
92
99
|
onError: (err) => {
|
|
93
100
|
console.error('Run failed:', err);
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
export function generateHtmlReport(reportData, collectionName) {
|
|
2
|
+
const summary = reportData.summary;
|
|
3
|
+
const requests = reportData.requests || [];
|
|
4
|
+
const passRate = summary.totalTests
|
|
5
|
+
? ((summary.passed / summary.totalTests) * 100).toFixed(1)
|
|
6
|
+
: "0";
|
|
7
|
+
return `
|
|
8
|
+
${buildHtmlStart()}
|
|
9
|
+
${buildHeader(collectionName)}
|
|
10
|
+
${buildSummary(summary, passRate)}
|
|
11
|
+
${buildRequests(requests)}
|
|
12
|
+
${buildFooter()}
|
|
13
|
+
${buildScript()}
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
function buildHtmlStart() {
|
|
19
|
+
return `
|
|
20
|
+
<!DOCTYPE html>
|
|
21
|
+
<html>
|
|
22
|
+
<head>
|
|
23
|
+
<meta charset="UTF-8" />
|
|
24
|
+
<title>Postmate Execution Report</title>
|
|
25
|
+
<style>
|
|
26
|
+
body {
|
|
27
|
+
font-family: "Segoe UI", Arial, sans-serif;
|
|
28
|
+
background-color: #f4f6f9;
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 20px;
|
|
31
|
+
color: #2c3e50;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.container { max-width: 1100px; margin: auto; }
|
|
35
|
+
|
|
36
|
+
.header {
|
|
37
|
+
background: #1f2937;
|
|
38
|
+
color: white;
|
|
39
|
+
padding: 20px;
|
|
40
|
+
border-radius: 8px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.summary {
|
|
44
|
+
display: flex;
|
|
45
|
+
gap: 15px;
|
|
46
|
+
margin: 20px 0;
|
|
47
|
+
flex-wrap: wrap;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.card {
|
|
51
|
+
flex: 1;
|
|
52
|
+
min-width: 160px;
|
|
53
|
+
background: white;
|
|
54
|
+
padding: 15px;
|
|
55
|
+
border-radius: 8px;
|
|
56
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
|
57
|
+
text-align: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.pass { color: #16a34a; }
|
|
61
|
+
.fail { color: #dc2626; }
|
|
62
|
+
|
|
63
|
+
.request {
|
|
64
|
+
background: white;
|
|
65
|
+
margin-bottom: 12px;
|
|
66
|
+
border-radius: 8px;
|
|
67
|
+
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.request-header {
|
|
71
|
+
padding: 12px 16px;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
display: flex;
|
|
74
|
+
justify-content: space-between;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.request-details {
|
|
78
|
+
display: none;
|
|
79
|
+
padding: 15px;
|
|
80
|
+
border-top: 1px solid #e5e7eb;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.badge-pass {
|
|
84
|
+
background: #dcfce7;
|
|
85
|
+
color: #166534;
|
|
86
|
+
padding: 4px 8px;
|
|
87
|
+
border-radius: 12px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.badge-fail {
|
|
91
|
+
background: #fee2e2;
|
|
92
|
+
color: #991b1b;
|
|
93
|
+
padding: 4px 8px;
|
|
94
|
+
border-radius: 12px;
|
|
95
|
+
}
|
|
96
|
+
.test-status-pass {
|
|
97
|
+
color: #16a34a;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.test-status-fail {
|
|
102
|
+
color: #dc2626;
|
|
103
|
+
font-weight: 600;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
</style>
|
|
107
|
+
</head>
|
|
108
|
+
<body>
|
|
109
|
+
<div class="container">
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
function buildHeader(collectionName) {
|
|
113
|
+
const logoBase64 = "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";
|
|
114
|
+
return `
|
|
115
|
+
<div class="header" style="
|
|
116
|
+
display:flex;
|
|
117
|
+
justify-content:space-between;
|
|
118
|
+
align-items:center;
|
|
119
|
+
">
|
|
120
|
+
<div style="display:flex;align-items:center;gap:14px;">
|
|
121
|
+
<img src="data:image/png;base64,${logoBase64}" style="height:50px;" />
|
|
122
|
+
<div>
|
|
123
|
+
<h1 style="margin:0;">Execution Report</h1>
|
|
124
|
+
<div style="font-size:13px;opacity:0.8;">
|
|
125
|
+
${collectionName}
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
<div style="font-size:12px;opacity:0.7;">
|
|
131
|
+
${new Date().toLocaleString()}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
function buildSummary(summary, passRate) {
|
|
138
|
+
return `
|
|
139
|
+
<div class="summary">
|
|
140
|
+
<div class="card">
|
|
141
|
+
<div>Total Requests</div>
|
|
142
|
+
<h2>${summary.totalRequests}</h2>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<div class="card">
|
|
146
|
+
<div>Total Tests</div>
|
|
147
|
+
<h2>${summary.totalTests}</h2>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div class="card">
|
|
151
|
+
<div>Passed</div>
|
|
152
|
+
<h2 class="pass">${summary.passed}</h2>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div class="card">
|
|
156
|
+
<div>Failed</div>
|
|
157
|
+
<h2 class="fail">${summary.failed}</h2>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div class="card">
|
|
161
|
+
<div>Pass Rate</div>
|
|
162
|
+
<h2>${passRate}%</h2>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
`;
|
|
166
|
+
}
|
|
167
|
+
function buildRequests(requests) {
|
|
168
|
+
return requests.map((req, index) => buildRequestCard(req, index)).join("");
|
|
169
|
+
}
|
|
170
|
+
function buildRequestCard(req, index) {
|
|
171
|
+
const hasFailure = req.tests?.some((t) => t.status === "Failed");
|
|
172
|
+
const dataLine = req.data
|
|
173
|
+
? `
|
|
174
|
+
<div style="
|
|
175
|
+
font-size:12px;
|
|
176
|
+
opacity:0.75;
|
|
177
|
+
margin-top:4px;
|
|
178
|
+
font-family: Consolas, monospace;
|
|
179
|
+
background:#f8fafc;
|
|
180
|
+
padding:6px;
|
|
181
|
+
border-radius:4px;
|
|
182
|
+
overflow-x:auto;
|
|
183
|
+
">
|
|
184
|
+
${escapeHtml(JSON.stringify(req.data, null, 2))}
|
|
185
|
+
</div>`
|
|
186
|
+
: "";
|
|
187
|
+
return `
|
|
188
|
+
<div class="request">
|
|
189
|
+
<div class="request-header" onclick="toggle(${index})">
|
|
190
|
+
<div>
|
|
191
|
+
<strong>${req.method}</strong> ${req.name}
|
|
192
|
+
<div style="font-size:12px;opacity:0.7;">${req.url}</div>
|
|
193
|
+
${dataLine}
|
|
194
|
+
</div>
|
|
195
|
+
<div>
|
|
196
|
+
${hasFailure
|
|
197
|
+
? `<span class="badge-fail">FAILED</span>`
|
|
198
|
+
: `<span class="badge-pass">PASSED</span>`}
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<div class="request-details" id="details-${index}">
|
|
203
|
+
<div style="font-size:13px;margin-bottom:8px;">
|
|
204
|
+
Status: <strong>${req.status}</strong> |
|
|
205
|
+
Duration: ${req.durationMs} ms
|
|
206
|
+
</div>
|
|
207
|
+
|
|
208
|
+
${(req.tests || []).map(buildTestRow).join("")}
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
`;
|
|
212
|
+
}
|
|
213
|
+
function escapeHtml(str) {
|
|
214
|
+
return str
|
|
215
|
+
.replace(/&/g, "&")
|
|
216
|
+
.replace(/</g, "<")
|
|
217
|
+
.replace(/>/g, ">");
|
|
218
|
+
}
|
|
219
|
+
function buildTestRow(test) {
|
|
220
|
+
return `
|
|
221
|
+
<div style="display:flex;justify-content:space-between;font-size:13px;padding:6px 0;">
|
|
222
|
+
<div>${test.description}</div>
|
|
223
|
+
<div class="${test.status === "Passed" ? "test-status-pass" : "test-status-fail"}">
|
|
224
|
+
${test.status.toUpperCase()}
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
`;
|
|
228
|
+
}
|
|
229
|
+
function buildFooter() {
|
|
230
|
+
return `
|
|
231
|
+
<div style="text-align:center;font-size:12px;margin-top:30px;opacity:0.6;">
|
|
232
|
+
Generated by Postmate CLI
|
|
233
|
+
</div>
|
|
234
|
+
`;
|
|
235
|
+
}
|
|
236
|
+
function buildScript() {
|
|
237
|
+
return `
|
|
238
|
+
<script>
|
|
239
|
+
function toggle(index) {
|
|
240
|
+
const el = document.getElementById("details-" + index);
|
|
241
|
+
el.style.display = el.style.display === "block" ? "none" : "block";
|
|
242
|
+
}
|
|
243
|
+
</script>
|
|
244
|
+
`;
|
|
245
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postmate/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Postmate CLI - Run API collections from terminal",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"author": "Shyam Naryan Yadav",
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@postmate/core": "^0.1.
|
|
18
|
+
"@postmate/core": "^0.1.17",
|
|
19
19
|
"chalk": "^5.6.2",
|
|
20
20
|
"commander": "^14.0.3"
|
|
21
21
|
},
|