Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
{
// 파일 저장 시 자동 포맷팅
"editor.formatOnSave": true,

// TypeScript/JavaScript 파일에 대한 기본 포맷터로 Prettier 사용
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

// Markdown 및 MDX 파일에 대한 ESLint 및 Prettier 비활성화
"[markdown]": {
"editor.formatOnSave": false,
Expand All @@ -23,21 +21,17 @@
"source.fixAll.eslint": "never"
}
},

// ESLint 설정
"eslint.enable": true,
"eslint.validate": ["javascript", "typescript"],

// 파일 저장 시 ESLint 자동 수정 (Markdown/MDX 제외)
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},

// Prettier 설정
"prettier.requireConfig": true,
"prettier.configPath": ".prettierrc",
"prettier.disableLanguages": ["markdown", "mdx"],

// TypeScript 설정
"typescript.tsdk": "node_modules/typescript/lib"
}
17 changes: 15 additions & 2 deletions bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ program
.description("Generate ITDOC test code based on LLM.")
.option("-a, --app <appPath>", "Path to the Express root app file.")
.option("-e, --env <envPath>", "Path to the .env file.")
.action(async (options: { env?: string; app?: string }) => {
.option(
"-l, --lang <language>",
"Output language for test generation: 'en' for English, 'ko' for Korean (default: 'ko')",
)
.action(async (options: { env?: string; app?: string; lang?: string }) => {
const envPath = options.env
? path.isAbsolute(options.env)
? options.env
Expand All @@ -74,13 +78,22 @@ program
process.exit(1)
}

const lang = options.lang?.toLowerCase()
const isEn = lang === "en"

if (lang && lang !== "en" && lang !== "ko") {
logger.error(`Invalid language option: ${lang}. Must be 'en' or 'ko'.`)
process.exit(1)
}

logger.box("ITDOC LLM START")
if (options.app) {
const appPath = resolvePath(options.app)

logger.info(`Running analysis based on Express app path: ${appPath}`)
logger.info(`Output language: ${isEn ? "English" : "Korean"}`)
try {
await generateByLLM(appPath, envPath)
await generateByLLM(appPath, envPath, isEn)
} catch (err) {
logger.error(`LLM generation failed: ${(err as Error).message}`)
process.exit(1)
Expand Down
69 changes: 69 additions & 0 deletions examples/express/__tests__/expressApp.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ describeAPI(
})
},
)

describeAPI(
HttpMethod.GET,
"/failed-test",
Expand All @@ -515,3 +516,71 @@ describeAPI(
})
},
)

describeAPI(
HttpMethod.POST,
"/uploads",
{
summary: "파일 업로드 API",
tag: "File",
description: "파일을 업로드합니다.",
},
targetApp,
(apiDoc) => {
const fileToUpload = "../expected/oas.json"

itDoc("파일 업로드 성공 (with filePath)", async () => {
await apiDoc
.test()
.req()
.file("업로드할 파일", {
path: require("path").join(__dirname, fileToUpload),
})
.res()
.status(HttpStatus.CREATED)
})

itDoc("파일 업로드 성공 (with Stream)", async () => {
const fs = require("fs")
const filePath = require("path").join(__dirname, fileToUpload)

await apiDoc
.test()
.req()
.file("업로드할 파일", {
stream: fs.createReadStream(filePath),
filename: "example-stream.txt",
})
.res()
.status(HttpStatus.CREATED)
})

itDoc("파일 업로드 성공 (with Buffer)", async () => {
const fs = require("fs")
const filePath = require("path").join(__dirname, fileToUpload)

await apiDoc
.test()
.req()
.file("업로드할 파일", {
buffer: fs.readFileSync(filePath),
filename: "example-buffer.txt",
})
.res()
.status(HttpStatus.CREATED)
})

itDoc("업로드할 파일을 지정하지 않으면 400에러가 뜬다", async () => {
await apiDoc
.test()
.prettyPrint()
.req()
.file()
.res()
.status(HttpStatus.BAD_REQUEST)
.body({
error: field("에러 메세지", "No file uploaded"),
})
})
},
)
64 changes: 64 additions & 0 deletions examples/express/expected/oas.json
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,70 @@
}
}
}
},
"/uploads": {
"post": {
"summary": "파일 업로드 API",
"tags": ["File"],
"description": "파일을 업로드합니다.",
"operationId": "postUploads",
"parameters": [
{
"name": "content-type",
"in": "header",
"schema": {
"type": "string",
"example": "application/octet-stream"
},
"required": false
}
],
"requestBody": {
"content": {
"application/octet-stream": {
"schema": {
"type": "string",
"format": "binary"
}
}
},
"required": true
},
"security": [{}],
"responses": {
"201": {
"description": "파일 업로드 성공 (with filePath)"
},
"400": {
"description": "업로드할 파일을 지정하지 않으면 400에러가 뜬다",
"content": {
"application/json; charset=utf-8": {
"schema": {
"type": "object",
"properties": {
"error": {
"type": "string",
"example": "No file uploaded",
"description": "에러 메세지"
}
},
"required": ["error"]
},
"examples": {
"업로드할 파일을 지정하지 않으면 400에러가 뜬다": {
"value": {
"error": {
"message": "업로드할 파일을 지정하지 않으면 400에러가 뜬다",
"code": "ERROR_400"
}
}
}
}
}
}
}
}
}
}
},
"components": {
Expand Down
23 changes: 23 additions & 0 deletions examples/express/expressApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,27 @@ app.get("/failed-test", (req, res) => {
})
})

app.post("/uploads", (req, res) => {
if (req.headers["content-type"] !== "application/octet-stream") {
return res.status(400).json({ error: "Invalid content type" })
}

let uploadedBytes = 0

req.on("data", (chunk) => {
uploadedBytes += chunk.length
})

req.on("end", () => {
if (uploadedBytes === 0) {
return res.status(400).json({ error: "No file uploaded" })
}
return res.status(201).json()
})

req.on("error", () => {
return res.status(500).json({ error: "Upload failed" })
})
})

module.exports = app
20 changes: 17 additions & 3 deletions itdoc-doc/docs/api-reference/interface.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,25 @@ apiDoc
### req()

Defines values used in API requests.
- `body(body: object)`: Set request body
- `header(headers: object)`: Set request headers
- `body(body: object)`: Set JSON request body
- `file(description: string, descriptor: { path?: string; buffer?: Buffer; stream?: Readable; filename?: string; contentType?: string })`: Send a single binary payload. Provide exactly one of `path`, `buffer`, or `stream`. Mutually exclusive with `body()`.
- `file(requestFile: DSLRequestFile)`: Advanced form for custom integrations (expects the same structure as the descriptor above).
- `header(headers: object)`: Set request headers (Content-Type is managed automatically for `.file()`).
- `pathParam(params: object)`: Set path parameters
- `queryParam(params: object)`: Set query parameters
- `expectStatus(status: HttpStatus)`: Set expected response status (**Required**)

```ts
apiDoc
.test()
.req()
.file("업로드할 파일", {
stream: fs.createReadStream(filePath),
filename: "sample.bin",
contentType: "application/octet-stream",
})
.res()
.status(HttpStatus.CREATED)
```

### res()

Expand Down
21 changes: 20 additions & 1 deletion itdoc-doc/docs/experiments/LLM.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,29 @@ Currently, source code-based automatic test generation is only supported for the
```bash
itdoc generate -a {YOUR_APP_FILE_PATH}
itdoc generate --app {YOUR_APP_FILE_PATH}

# Generate tests in English(default : korean)
itdoc generate -a {YOUR_APP_FILE_PATH} -l en
itdoc generate --app {YOUR_APP_FILE_PATH} --lang en
```

| Option | Description |
|------------------------------------------------------------------------|--------------------------------|
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--app (-a)</span> | Root app source code file path |
| <span style={{color: '#0d6efd', fontWeight: 'bold'}}>--lang (-l)</span> | Output language: `en` for English, `ko` for Korean (default: `ko`) |

When you run this command, it analyzes the Express application defined in `{YOUR_APP_FILE_PATH}` and automatically generates tests for the API endpoints in that application.

:::tip[Language Selection]
- By default, test descriptions and comments are generated in **Korean** (`ko`).
- Use the `--lang en` (or `-l en`) option to generate all test content in **English**.
:::

**Example:**
```bash
# Korean output (default)
itdoc generate -a ./app.js

When you run this command, it analyzes the Express application defined in `{YOUR_APP_FILE_PATH}` and automatically generates tests for the API endpoints in that application.
# English output
itdoc generate -a ./app.js --lang en
```
4 changes: 2 additions & 2 deletions itdoc-doc/docs/guides/configuration.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 4
sidebar_position: 9999
toc_max_heading_level: 4
---

Expand Down Expand Up @@ -38,4 +38,4 @@ This section provides detailed explanations of each `itdoc` configuration option
|---------------|-----------------------------------------------------|----------------------------------------------------------------------|
| `baseUrl` | The base URL used for generating links in API docs. | `"http://localhost:8080"` |
| `title` | The title displayed in the API documentation. | `"API Document"` |
| `description` | The description displayed in the API documentation. | `"You can change the description by specifying it in package.json."` |
| `description` | The description displayed in the API documentation. | `"You can change the description by specifying it in package.json."` |
Loading
Loading