playwright-api-logger 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maіevskyi Leonid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,216 @@
1
+ <p align="center">
2
+ <img src="https://playwright.dev/img/playwright-logo.svg" width="80" alt="Playwright Logo" />
3
+ </p>
4
+
5
+ <h1 align="center">playwright-api-logger</h1>
6
+
7
+ <p align="center">
8
+ Comprehensive API request/response logger with curl export for Playwright tests
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/playwright-api-logger"><img src="https://img.shields.io/npm/v/playwright-api-logger.svg?style=flat-square&color=cb3837" alt="npm version" /></a>
13
+ <a href="https://www.npmjs.com/package/playwright-api-logger"><img src="https://img.shields.io/npm/dm/playwright-api-logger.svg?style=flat-square&color=blue" alt="npm downloads" /></a>
14
+ <a href="https://github.com/AZANIR/playwright-api-logger/blob/master/LICENSE"><img src="https://img.shields.io/github/license/AZANIR/playwright-api-logger?style=flat-square" alt="license" /></a>
15
+ <a href="https://playwright.dev/"><img src="https://img.shields.io/badge/Playwright-%3E%3D1.40-45ba4b?style=flat-square&logo=playwright" alt="Playwright" /></a>
16
+ <a href="https://www.typescriptlang.org/"><img src="https://img.shields.io/badge/TypeScript-5.0+-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /></a>
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## How It Works
22
+
23
+ ```mermaid
24
+ flowchart TD
25
+ subgraph T[Playwright Test]
26
+ F[Fixture setup]
27
+ C[API Call (GET / POST)]
28
+ end
29
+
30
+ subgraph L[Logging & API layer]
31
+ AL[ApiLogger (per test)]
32
+ B[BaseApi Controller]
33
+ CG[Curl Generator]
34
+ end
35
+
36
+ subgraph FS[File system]
37
+ LOG[logs/TEST_*.log { request, response, curl, duration }]
38
+ RC[Ready-to-use curl for Postman / terminal]
39
+ end
40
+
41
+ %% test flow
42
+ F --> AL
43
+ C --> B
44
+
45
+ %% logging interaction
46
+ B --> AL
47
+ AL --> LOG
48
+
49
+ %% curl generation
50
+ B --> CG
51
+ CG --> RC
52
+ ```
53
+
54
+ `API_LOGS=true` → **Logging ON** (files created in `logs/`)
55
+ `API_LOGS=false` → **Logging OFF** (zero overhead, default)
56
+
57
+ ## Features
58
+
59
+ - **Full Logging** — method, URL, headers, request/response body, status, timing
60
+ - **Curl Export** — copy from log, paste into terminal or import into Postman
61
+ - **Env Control** — `API_LOGS=true/false` (default: `false`, zero overhead when off)
62
+ - **Context Tracking** — setup / test / teardown phases
63
+ - **Token Masking** — Authorization headers are automatically masked
64
+ - **Form Data** — JSON, URL-encoded, and multipart/form-data support
65
+ - **Error Resilient** — logging never breaks your tests
66
+
67
+ ## Installation
68
+
69
+ ```bash
70
+ npm install playwright-api-logger
71
+ ```
72
+
73
+ ## Quick Start
74
+
75
+ ### Step 1. Add logger to your fixture
76
+
77
+ ```typescript
78
+ import { createApiLogger } from 'playwright-api-logger';
79
+
80
+ export const test = base.extend({
81
+ apiClient: async ({ request }, use, testInfo) => {
82
+ const apiClient = new ApiClient(request);
83
+
84
+ if (process.env.API_LOGS === 'true') {
85
+ const logger = createApiLogger(testInfo.title, 'test');
86
+ apiClient.setApiLogger(logger);
87
+ await use(apiClient);
88
+ logger.finalize(testInfo.status === 'passed' ? 'PASSED' : 'FAILED');
89
+ } else {
90
+ await use(apiClient);
91
+ }
92
+ },
93
+ });
94
+ ```
95
+
96
+ ### Step 2. Add logging to your base API controller
97
+
98
+ ```typescript
99
+ import { ApiLogger } from 'playwright-api-logger';
100
+
101
+ class BaseApiController {
102
+ protected apiLogger: ApiLogger | null = null;
103
+
104
+ setApiLogger(logger: ApiLogger): void {
105
+ this.apiLogger = logger;
106
+ }
107
+
108
+ async get(url: string, headers?: Record<string, string>) {
109
+ const startTime = Date.now();
110
+ const response = await this.request.get(url, { headers });
111
+ const duration = Date.now() - startTime;
112
+
113
+ if (this.apiLogger?.isEnabled()) {
114
+ const body = await response.json().catch(() => response.text());
115
+ this.apiLogger.logApiCall(
116
+ 'GET', url, headers, undefined,
117
+ response.status(), undefined, body, duration
118
+ );
119
+ }
120
+
121
+ return response;
122
+ }
123
+ }
124
+ ```
125
+
126
+ ### Step 3. Enable via environment variable
127
+
128
+ ```bash
129
+ # .env
130
+ API_LOGS=false
131
+ ```
132
+
133
+ ```bash
134
+ # Run with logging enabled
135
+ API_LOGS=true npx playwright test
136
+ ```
137
+
138
+ ## Log Output
139
+
140
+ Logs are saved to `logs/` directory:
141
+
142
+ ```
143
+ logs/
144
+ TEST_my-test-name_2026-03-16T12-00-00.log
145
+ SETUP_auth-setup_2026-03-16T12-00-00.log
146
+ TEARDOWN_cleanup_2026-03-16T12-00-00.log
147
+ ```
148
+
149
+ Each log entry is a JSON object:
150
+
151
+ ```json
152
+ {
153
+ "timestamp": "2026-03-16T12:00:00.000Z",
154
+ "testName": "my-test-name",
155
+ "context": "test",
156
+ "request": {
157
+ "method": "POST",
158
+ "url": "https://api.example.com/users",
159
+ "headers": { "Content-Type": "application/json" },
160
+ "body": { "name": "John" }
161
+ },
162
+ "response": {
163
+ "status": 201,
164
+ "body": { "id": 1, "name": "John" }
165
+ },
166
+ "duration": 150,
167
+ "curl": "curl -X POST 'https://api.example.com/users' -H 'Content-Type: application/json' --data '{\"name\":\"John\"}'"
168
+ }
169
+ ```
170
+
171
+ ## API Reference
172
+
173
+ ### Factory Functions
174
+
175
+ | Function | Description |
176
+ |----------|-------------|
177
+ | `createApiLogger(testName, context?)` | Create logger (context default: `'test'`) |
178
+ | `createSetupLogger(testName)` | Create logger with `'setup'` context |
179
+ | `createTeardownLogger(testName)` | Create logger with `'teardown'` context |
180
+
181
+ ### `ApiLogger`
182
+
183
+ | Method | Description |
184
+ |--------|-------------|
185
+ | `logApiCall(method, url, reqHeaders, reqBody, status, resHeaders, resBody, duration)` | Log complete request + response |
186
+ | `logRequest(method, url, headers?, body?)` | Log request (pair with `logResponse`) |
187
+ | `logResponse(status, headers?, body?)` | Log response (pair with `logRequest`) |
188
+ | `isEnabled()` | Check if logging is active |
189
+ | `finalize(result, additionalInfo?)` | Write test result (`PASSED` / `FAILED` / `SKIPPED`) |
190
+ | `getLogFilePath()` | Get current log file path |
191
+
192
+ ### `CurlGenerator`
193
+
194
+ | Method | Description |
195
+ |--------|-------------|
196
+ | `CurlGenerator.generate(requestData, maskAuth?)` | Generate curl command string |
197
+
198
+ ## Configuration
199
+
200
+ | Env Variable | Default | Description |
201
+ |-------------|---------|-------------|
202
+ | `API_LOGS` | `false` | Set to `'true'` to enable logging |
203
+
204
+ ```typescript
205
+ // LoggerConfig
206
+ {
207
+ testName?: string; // Test name (default: 'unknown-test')
208
+ context?: LogContext; // 'setup' | 'test' | 'teardown'
209
+ logDirectory?: string; // Custom log dir (default: 'logs/')
210
+ maskAuthTokens?: boolean; // Mask auth headers (default: true)
211
+ }
212
+ ```
213
+
214
+ ## License
215
+
216
+ MIT
@@ -0,0 +1,78 @@
1
+ /**
2
+ * API Logger for capturing and logging HTTP requests/responses
3
+ * Features:
4
+ * - Comprehensive request/response logging
5
+ * - Curl command generation for manual testing
6
+ * - Environment-based enable/disable via API_LOGS
7
+ * - Automatic file logging with JSON format
8
+ * - Test context tracking (setup/test/teardown)
9
+ */
10
+ import { LogContext, LoggerConfig } from './types';
11
+ export declare class ApiLogger {
12
+ private enabled;
13
+ private testName;
14
+ private context;
15
+ private logDirectory;
16
+ private logFilePath;
17
+ private maskAuthTokens;
18
+ private currentRequest;
19
+ private requestStartTime;
20
+ constructor(config?: LoggerConfig);
21
+ /**
22
+ * Get default log directory path
23
+ */
24
+ private getDefaultLogDirectory;
25
+ /**
26
+ * Initialize log file and directory
27
+ */
28
+ private initializeLogFile;
29
+ /**
30
+ * Log an API call with request and response
31
+ */
32
+ logApiCall(method: string, url: string, requestHeaders: Record<string, string | string[]> | undefined, requestBody: any, status: number, responseHeaders: Record<string, string> | undefined, responseBody: any, duration: number): void;
33
+ /**
34
+ * Log just the request part (when response isn't available yet)
35
+ */
36
+ logRequest(method: string, url: string, headers?: Record<string, string | string[]>, body?: any): void;
37
+ /**
38
+ * Log just the response part (pairs with logRequest)
39
+ */
40
+ logResponse(status: number, headers?: Record<string, string>, body?: any): void;
41
+ /**
42
+ * Write log entry to file
43
+ */
44
+ private writeLogEntry;
45
+ /**
46
+ * Generate ISO timestamp for filenames
47
+ */
48
+ private generateTimestamp;
49
+ /**
50
+ * Sanitize test name for use in filename
51
+ */
52
+ private sanitizeTestName;
53
+ /**
54
+ * Get the current log file path
55
+ */
56
+ getLogFilePath(): string | null;
57
+ /**
58
+ * Check if logger is enabled
59
+ */
60
+ isEnabled(): boolean;
61
+ /**
62
+ * Finalize logging for test completion
63
+ */
64
+ finalize(result: 'PASSED' | 'FAILED' | 'SKIPPED', additionalInfo?: Record<string, any>): void;
65
+ }
66
+ /**
67
+ * Factory function for creating test-context loggers
68
+ */
69
+ export declare function createApiLogger(testName: string, context?: LogContext): ApiLogger;
70
+ /**
71
+ * Factory for setup context
72
+ */
73
+ export declare function createSetupLogger(testName: string): ApiLogger;
74
+ /**
75
+ * Factory for teardown context
76
+ */
77
+ export declare function createTeardownLogger(testName: string): ApiLogger;
78
+ //# sourceMappingURL=ApiLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiLogger.d.ts","sourceRoot":"","sources":["../src/ApiLogger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EACL,UAAU,EACV,YAAY,EAIb,MAAM,SAAS,CAAC;AAEjB,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,gBAAgB,CAAuB;gBAEnC,MAAM,GAAE,YAAiB;IAcrC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;IACH,UAAU,CACR,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,SAAS,EAC7D,WAAW,EAAE,GAAG,EAChB,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,YAAY,EAAE,GAAG,EACjB,QAAQ,EAAE,MAAM,GACf,IAAI;IAmDP;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAStG;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI;IAsB/E;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;CAuB9F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,UAAmB,GAAG,SAAS,CAEzF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAE7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAEhE"}
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /**
3
+ * API Logger for capturing and logging HTTP requests/responses
4
+ * Features:
5
+ * - Comprehensive request/response logging
6
+ * - Curl command generation for manual testing
7
+ * - Environment-based enable/disable via API_LOGS
8
+ * - Automatic file logging with JSON format
9
+ * - Test context tracking (setup/test/teardown)
10
+ */
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ApiLogger = void 0;
16
+ exports.createApiLogger = createApiLogger;
17
+ exports.createSetupLogger = createSetupLogger;
18
+ exports.createTeardownLogger = createTeardownLogger;
19
+ const fs_1 = __importDefault(require("fs"));
20
+ const path_1 = __importDefault(require("path"));
21
+ const CurlGenerator_1 = require("./CurlGenerator");
22
+ class ApiLogger {
23
+ constructor(config = {}) {
24
+ this.logFilePath = null;
25
+ this.currentRequest = null;
26
+ this.requestStartTime = null;
27
+ // Check if logging is enabled via environment variable
28
+ this.enabled = process.env.API_LOGS === 'true';
29
+ this.testName = config.testName || 'unknown-test';
30
+ this.context = config.context || 'test';
31
+ this.logDirectory = config.logDirectory || this.getDefaultLogDirectory();
32
+ this.maskAuthTokens = config.maskAuthTokens ?? true;
33
+ if (this.enabled) {
34
+ this.initializeLogFile();
35
+ }
36
+ }
37
+ /**
38
+ * Get default log directory path
39
+ */
40
+ getDefaultLogDirectory() {
41
+ return path_1.default.join(process.cwd(), 'logs');
42
+ }
43
+ /**
44
+ * Initialize log file and directory
45
+ */
46
+ initializeLogFile() {
47
+ try {
48
+ if (!fs_1.default.existsSync(this.logDirectory)) {
49
+ fs_1.default.mkdirSync(this.logDirectory, { recursive: true });
50
+ }
51
+ const timestamp = this.generateTimestamp();
52
+ const sanitizedTestName = this.sanitizeTestName(this.testName);
53
+ const filename = `${this.context.toUpperCase()}_${sanitizedTestName}_${timestamp}.log`;
54
+ this.logFilePath = path_1.default.join(this.logDirectory, filename);
55
+ if (!fs_1.default.existsSync(this.logFilePath)) {
56
+ fs_1.default.writeFileSync(this.logFilePath, '');
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn('[ApiLogger] Failed to initialize log file:', error);
61
+ this.logFilePath = null;
62
+ }
63
+ }
64
+ /**
65
+ * Log an API call with request and response
66
+ */
67
+ logApiCall(method, url, requestHeaders, requestBody, status, responseHeaders, responseBody, duration) {
68
+ if (!this.enabled) {
69
+ return;
70
+ }
71
+ try {
72
+ // Extract content type from headers
73
+ let contentType;
74
+ if (requestHeaders) {
75
+ for (const [key, value] of Object.entries(requestHeaders)) {
76
+ if (key.toLowerCase() === 'content-type') {
77
+ contentType = Array.isArray(value) ? value[0] : value;
78
+ break;
79
+ }
80
+ }
81
+ }
82
+ const requestData = {
83
+ method,
84
+ url,
85
+ headers: requestHeaders,
86
+ body: requestBody,
87
+ contentType,
88
+ };
89
+ const responseData = {
90
+ status,
91
+ headers: responseHeaders,
92
+ body: responseBody,
93
+ };
94
+ // Generate curl command
95
+ const curl = CurlGenerator_1.CurlGenerator.generate(requestData, this.maskAuthTokens);
96
+ // Create log entry
97
+ const logEntry = {
98
+ timestamp: new Date().toISOString(),
99
+ testName: this.testName,
100
+ context: this.context,
101
+ request: requestData,
102
+ response: responseData,
103
+ duration,
104
+ curl,
105
+ };
106
+ this.writeLogEntry(logEntry);
107
+ }
108
+ catch (error) {
109
+ console.warn('[ApiLogger] Error logging API call:', error);
110
+ }
111
+ }
112
+ /**
113
+ * Log just the request part (when response isn't available yet)
114
+ */
115
+ logRequest(method, url, headers, body) {
116
+ if (!this.enabled) {
117
+ return;
118
+ }
119
+ this.currentRequest = { method, url, headers, body };
120
+ this.requestStartTime = Date.now();
121
+ }
122
+ /**
123
+ * Log just the response part (pairs with logRequest)
124
+ */
125
+ logResponse(status, headers, body) {
126
+ if (!this.enabled || !this.currentRequest) {
127
+ return;
128
+ }
129
+ const duration = this.requestStartTime ? Date.now() - this.requestStartTime : 0;
130
+ this.logApiCall(this.currentRequest.method, this.currentRequest.url, this.currentRequest.headers, this.currentRequest.body, status, headers, body, duration);
131
+ this.currentRequest = null;
132
+ this.requestStartTime = null;
133
+ }
134
+ /**
135
+ * Write log entry to file
136
+ */
137
+ writeLogEntry(entry) {
138
+ try {
139
+ if (!this.logFilePath) {
140
+ return;
141
+ }
142
+ const logLine = JSON.stringify(entry, null, 2);
143
+ fs_1.default.appendFileSync(this.logFilePath, logLine + '\n\n');
144
+ }
145
+ catch (error) {
146
+ console.warn('[ApiLogger] Failed to write log file:', error);
147
+ }
148
+ }
149
+ /**
150
+ * Generate ISO timestamp for filenames
151
+ */
152
+ generateTimestamp() {
153
+ const now = new Date();
154
+ return now
155
+ .toISOString()
156
+ .replace(/[:.]/g, '-')
157
+ .replace('T', 'T')
158
+ .split('.')[0];
159
+ }
160
+ /**
161
+ * Sanitize test name for use in filename
162
+ */
163
+ sanitizeTestName(name) {
164
+ return name
165
+ .toLowerCase()
166
+ .replace(/[^a-z0-9-]/g, '-')
167
+ .replace(/-+/g, '-')
168
+ .replace(/^-|-$/g, '')
169
+ .substring(0, 80);
170
+ }
171
+ /**
172
+ * Get the current log file path
173
+ */
174
+ getLogFilePath() {
175
+ return this.logFilePath;
176
+ }
177
+ /**
178
+ * Check if logger is enabled
179
+ */
180
+ isEnabled() {
181
+ return this.enabled;
182
+ }
183
+ /**
184
+ * Finalize logging for test completion
185
+ */
186
+ finalize(result, additionalInfo) {
187
+ if (!this.enabled) {
188
+ return;
189
+ }
190
+ try {
191
+ const finalizationEntry = {
192
+ timestamp: new Date().toISOString(),
193
+ step: 'TEST_FINALIZATION',
194
+ testName: this.testName,
195
+ context: this.context,
196
+ result,
197
+ logFilePath: this.logFilePath,
198
+ additionalInfo,
199
+ };
200
+ if (this.logFilePath) {
201
+ fs_1.default.appendFileSync(this.logFilePath, JSON.stringify(finalizationEntry, null, 2) + '\n\n');
202
+ }
203
+ }
204
+ catch (error) {
205
+ console.warn('[ApiLogger] Error finalizing log:', error);
206
+ }
207
+ }
208
+ }
209
+ exports.ApiLogger = ApiLogger;
210
+ /**
211
+ * Factory function for creating test-context loggers
212
+ */
213
+ function createApiLogger(testName, context = 'test') {
214
+ return new ApiLogger({ testName, context });
215
+ }
216
+ /**
217
+ * Factory for setup context
218
+ */
219
+ function createSetupLogger(testName) {
220
+ return new ApiLogger({ testName, context: 'setup' });
221
+ }
222
+ /**
223
+ * Factory for teardown context
224
+ */
225
+ function createTeardownLogger(testName) {
226
+ return new ApiLogger({ testName, context: 'teardown' });
227
+ }
228
+ //# sourceMappingURL=ApiLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiLogger.js","sourceRoot":"","sources":["../src/ApiLogger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Curl command generator from HTTP request data
3
+ * Converts captured request details into ready-to-use curl commands
4
+ */
5
+ export interface RequestData {
6
+ method: string;
7
+ url: string;
8
+ headers?: Record<string, string | string[]>;
9
+ body?: any;
10
+ params?: Record<string, string | number | boolean>;
11
+ contentType?: string;
12
+ }
13
+ export declare class CurlGenerator {
14
+ /**
15
+ * Generate a curl command from request data
16
+ * @param requestData - The request information to convert
17
+ * @param maskAuth - Whether to mask Authorization headers (default: true)
18
+ * @returns A properly formatted curl command string
19
+ */
20
+ static generate(requestData: RequestData, maskAuth?: boolean): string;
21
+ /**
22
+ * Get content type from headers or contentType parameter
23
+ */
24
+ private static getContentType;
25
+ /**
26
+ * Convert body object to URL-encoded form string
27
+ */
28
+ private static bodyToFormString;
29
+ /**
30
+ * Generate multipart form fields for curl -F flag
31
+ */
32
+ private static generateMultipartFields;
33
+ /**
34
+ * Escape URL special characters (except for safe URL characters)
35
+ */
36
+ private static escapeUrl;
37
+ /**
38
+ * Escape string content in curl --data parameter
39
+ */
40
+ private static escapeBodyString;
41
+ /**
42
+ * Mask sensitive tokens/credentials (keep first 20 and last 10 chars)
43
+ */
44
+ private static maskToken;
45
+ /**
46
+ * Normalize headers from various formats to array of tuples
47
+ */
48
+ private static normalizeHeaders;
49
+ /**
50
+ * Determine if a header should be included in curl
51
+ */
52
+ private static shouldSkipHeader;
53
+ /**
54
+ * Determine if HTTP method typically includes a request body
55
+ */
56
+ private static shouldIncludeBody;
57
+ /**
58
+ * Format curl command for display (no-op, kept for API compatibility)
59
+ */
60
+ static formatForDisplay(curl: string): string;
61
+ /**
62
+ * Format curl command as single line (for easy copying)
63
+ */
64
+ static formatAsOneLine(curl: string): string;
65
+ }
66
+ //# sourceMappingURL=CurlGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CurlGenerator.d.ts","sourceRoot":"","sources":["../src/CurlGenerator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,aAAa;IACxB;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,GAAE,OAAc,GAAG,MAAM;IAyC3E;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAc7B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAe/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAuBtC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IASxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAiB/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAY/B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAKhC;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7C;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAG7C"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /**
3
+ * Curl command generator from HTTP request data
4
+ * Converts captured request details into ready-to-use curl commands
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.CurlGenerator = void 0;
8
+ class CurlGenerator {
9
+ /**
10
+ * Generate a curl command from request data
11
+ * @param requestData - The request information to convert
12
+ * @param maskAuth - Whether to mask Authorization headers (default: true)
13
+ * @returns A properly formatted curl command string
14
+ */
15
+ static generate(requestData, maskAuth = true) {
16
+ const { method, url, headers = {}, body, contentType } = requestData;
17
+ let curl = `curl -X ${method.toUpperCase()} '${this.escapeUrl(url)}'`;
18
+ // Detect content type
19
+ const contentTypeHeader = this.getContentType(headers, contentType);
20
+ // Add headers (except Content-Type for multipart, curl handles it)
21
+ const headerEntries = this.normalizeHeaders(headers);
22
+ for (const [key, value] of headerEntries) {
23
+ // Skip Content-Type for multipart, curl generates it automatically with -F
24
+ if (contentTypeHeader.includes('multipart') && key.toLowerCase() === 'content-type') {
25
+ continue;
26
+ }
27
+ const headerValue = maskAuth && key.toLowerCase() === 'authorization'
28
+ ? this.maskToken(value)
29
+ : value;
30
+ curl += ` -H '${key}: ${headerValue}'`;
31
+ }
32
+ // Add body for methods that typically have bodies
33
+ if (body && this.shouldIncludeBody(method)) {
34
+ if (contentTypeHeader.includes('multipart')) {
35
+ // Multipart form data - use -F flag
36
+ curl += this.generateMultipartFields(body);
37
+ }
38
+ else if (contentTypeHeader.includes('form-urlencoded')) {
39
+ // URL-encoded form data - use --data
40
+ const formString = this.bodyToFormString(body);
41
+ curl += ` --data '${this.escapeBodyString(formString)}'`;
42
+ }
43
+ else {
44
+ // JSON or other data - use --data with JSON
45
+ const bodyString = typeof body === 'string' ? body : JSON.stringify(body);
46
+ curl += ` --data '${this.escapeBodyString(bodyString)}'`;
47
+ }
48
+ }
49
+ return curl;
50
+ }
51
+ /**
52
+ * Get content type from headers or contentType parameter
53
+ */
54
+ static getContentType(headers, contentType) {
55
+ if (contentType) {
56
+ return contentType;
57
+ }
58
+ for (const [key, value] of Object.entries(headers)) {
59
+ if (key.toLowerCase() === 'content-type') {
60
+ return Array.isArray(value) ? value[0] : value;
61
+ }
62
+ }
63
+ return 'application/json';
64
+ }
65
+ /**
66
+ * Convert body object to URL-encoded form string
67
+ */
68
+ static bodyToFormString(body) {
69
+ if (typeof body === 'string') {
70
+ return body;
71
+ }
72
+ const params = new URLSearchParams();
73
+ if (typeof body === 'object' && body !== null) {
74
+ for (const [key, value] of Object.entries(body)) {
75
+ params.append(key, String(value));
76
+ }
77
+ }
78
+ return params.toString();
79
+ }
80
+ /**
81
+ * Generate multipart form fields for curl -F flag
82
+ */
83
+ static generateMultipartFields(body) {
84
+ if (typeof body === 'string') {
85
+ return ` --data '${this.escapeBodyString(body)}'`;
86
+ }
87
+ let result = '';
88
+ if (typeof body === 'object' && body !== null) {
89
+ for (const [key, value] of Object.entries(body)) {
90
+ if (value && typeof value === 'object' && 'path' in value) {
91
+ // File field - use -F 'key=@filepath'
92
+ const filePath = value.path;
93
+ result += ` -F '${key}=@${filePath}'`;
94
+ }
95
+ else {
96
+ // Regular field - use -F 'key=value'
97
+ const fieldValue = String(value).replace(/'/g, "'\\''");
98
+ result += ` -F '${key}=${fieldValue}'`;
99
+ }
100
+ }
101
+ }
102
+ return result || ` --data '${this.escapeBodyString(JSON.stringify(body))}'`;
103
+ }
104
+ /**
105
+ * Escape URL special characters (except for safe URL characters)
106
+ */
107
+ static escapeUrl(url) {
108
+ return url.replace(/"/g, '\\"');
109
+ }
110
+ /**
111
+ * Escape string content in curl --data parameter
112
+ */
113
+ static escapeBodyString(str) {
114
+ return str.replace(/'/g, "'\\''");
115
+ }
116
+ /**
117
+ * Mask sensitive tokens/credentials (keep first 20 and last 10 chars)
118
+ */
119
+ static maskToken(token) {
120
+ if (token.length <= 30) {
121
+ return '***masked***';
122
+ }
123
+ const start = token.substring(0, 20);
124
+ const end = token.substring(token.length - 10);
125
+ return `${start}...${end}`;
126
+ }
127
+ /**
128
+ * Normalize headers from various formats to array of tuples
129
+ */
130
+ static normalizeHeaders(headers) {
131
+ const normalized = [];
132
+ for (const [key, value] of Object.entries(headers)) {
133
+ if (!value || this.shouldSkipHeader(key)) {
134
+ continue;
135
+ }
136
+ const headerValue = Array.isArray(value) ? value.join(', ') : String(value);
137
+ if (headerValue) {
138
+ normalized.push([key, headerValue]);
139
+ }
140
+ }
141
+ return normalized.sort((a, b) => a[0].localeCompare(b[0]));
142
+ }
143
+ /**
144
+ * Determine if a header should be included in curl
145
+ */
146
+ static shouldSkipHeader(headerName) {
147
+ const skipHeaders = [
148
+ 'connection',
149
+ 'content-length',
150
+ 'host',
151
+ 'origin',
152
+ 'referer',
153
+ 'user-agent',
154
+ ];
155
+ return skipHeaders.includes(headerName.toLowerCase());
156
+ }
157
+ /**
158
+ * Determine if HTTP method typically includes a request body
159
+ */
160
+ static shouldIncludeBody(method) {
161
+ const methodsWithBody = ['POST', 'PUT', 'PATCH'];
162
+ return methodsWithBody.includes(method.toUpperCase());
163
+ }
164
+ /**
165
+ * Format curl command for display (no-op, kept for API compatibility)
166
+ */
167
+ static formatForDisplay(curl) {
168
+ return curl;
169
+ }
170
+ /**
171
+ * Format curl command as single line (for easy copying)
172
+ */
173
+ static formatAsOneLine(curl) {
174
+ return curl.replace(/\s+\\\n\s+/g, ' ');
175
+ }
176
+ }
177
+ exports.CurlGenerator = CurlGenerator;
178
+ //# sourceMappingURL=CurlGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CurlGenerator.js","sourceRoot":"","sources":["../src/CurlGenerator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { ApiLogger, createApiLogger, createSetupLogger, createTeardownLogger } from './ApiLogger';
2
+ export { CurlGenerator } from './CurlGenerator';
3
+ export type { LoggerConfig, RequestLogData, ResponseLogData, LogEntry, LogContext } from './types';
4
+ export type { RequestData } from './CurlGenerator';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnG,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CurlGenerator = exports.createTeardownLogger = exports.createSetupLogger = exports.createApiLogger = exports.ApiLogger = void 0;
4
+ var ApiLogger_1 = require("./ApiLogger");
5
+ Object.defineProperty(exports, "ApiLogger", { enumerable: true, get: function () { return ApiLogger_1.ApiLogger; } });
6
+ Object.defineProperty(exports, "createApiLogger", { enumerable: true, get: function () { return ApiLogger_1.createApiLogger; } });
7
+ Object.defineProperty(exports, "createSetupLogger", { enumerable: true, get: function () { return ApiLogger_1.createSetupLogger; } });
8
+ Object.defineProperty(exports, "createTeardownLogger", { enumerable: true, get: function () { return ApiLogger_1.createTeardownLogger; } });
9
+ var CurlGenerator_1 = require("./CurlGenerator");
10
+ Object.defineProperty(exports, "CurlGenerator", { enumerable: true, get: function () { return CurlGenerator_1.CurlGenerator; } });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAAkG;AAAzF,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAC5E,iDAAgD;AAAvC,8GAAA,aAAa,OAAA"}
@@ -0,0 +1,29 @@
1
+ export type LogContext = 'setup' | 'test' | 'teardown';
2
+ export interface LoggerConfig {
3
+ testName?: string;
4
+ context?: LogContext;
5
+ logDirectory?: string;
6
+ maskAuthTokens?: boolean;
7
+ }
8
+ export interface RequestLogData {
9
+ method: string;
10
+ url: string;
11
+ headers?: Record<string, string | string[]>;
12
+ body?: any;
13
+ contentType?: string;
14
+ }
15
+ export interface ResponseLogData {
16
+ status: number;
17
+ headers?: Record<string, string>;
18
+ body?: any;
19
+ }
20
+ export interface LogEntry {
21
+ timestamp: string;
22
+ testName: string;
23
+ context: LogContext;
24
+ request: RequestLogData;
25
+ response: ResponseLogData;
26
+ duration: number;
27
+ curl: string;
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "playwright-api-logger",
3
+ "version": "1.0.0",
4
+ "description": "Comprehensive API request/response logger with curl export for Playwright tests",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "playwright",
16
+ "api",
17
+ "logger",
18
+ "curl",
19
+ "testing",
20
+ "postman",
21
+ "form-data",
22
+ "multipart"
23
+ ],
24
+ "author": "AZANIR",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/AZANIR/playwright-api-logger.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/AZANIR/playwright-api-logger/issues"
32
+ },
33
+ "homepage": "https://github.com/AZANIR/playwright-api-logger#readme",
34
+ "peerDependencies": {
35
+ "@playwright/test": ">=1.40.0"
36
+ },
37
+ "devDependencies": {
38
+ "@playwright/test": "^1.58.0",
39
+ "@types/node": "^25.5.0",
40
+ "typescript": "^5.0.0"
41
+ }
42
+ }