-
Notifications
You must be signed in to change notification settings - Fork 3
feat: add wrapper-based API testing approach #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
json-choi
wants to merge
14
commits into
develop
Choose a base branch
from
241-feature-add-decorator-based-api-testing-support-for-enhanced
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 9 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
6130974
fix: og_image is not working (#231)
wnghdcjfe ff22da5
fix: resolve issue causing LLM script to not run properly (#235)
wnghdcjfe 8e2bc85
chore(main): release 0.4.1
github-actions[bot] 0acfa8f
fix: ensure header keys are case-insensitive (#251)
PENEKhun fe7d3a2
fix: resolve syntax error in generated openapi json (#253)
PENEKhun 30b9065
fix: functional response validation failure (#246)
PENEKhun 81879ce
feat: add wrapper-based API testing approach (draft/WIP)
json-choi 4d5e8ba
chore: pnpm install
json-choi 172be58
fix: resolve ESLint errors in wrapper tests
json-choi 4ab2a00
feat: add comprehensive documentation for wrapper-based API testing
json-choi 7f6535d
fix: rollback
json-choi b360fd4
Delete .serena/project.yml
json-choi 98714d9
Delete .serena/.gitignore
json-choi 5438398
fix: rollback
json-choi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| {".":"0.4.0"} | ||
| {".":"0.4.1"} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
211 changes: 211 additions & 0 deletions
211
examples/express-ts/src/__tests__/product.wrapper.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| /** | ||
| * Product API Tests using wrapTest wrapper approach | ||
| * | ||
| * This demonstrates the new high-order function wrapping method | ||
| * that automatically captures HTTP requests/responses | ||
| */ | ||
|
|
||
| import { app } from "../index" | ||
| import { wrapTest, request } from "itdoc" | ||
|
|
||
| // Create wrapped test function | ||
| const apiTest = wrapTest(it) | ||
|
|
||
| describe("Product API - Wrapper Approach", () => { | ||
| describe("GET /api/products/:id", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Get product by ID", | ||
| tags: ["Products"], | ||
| description: "Retrieves a specific product by its ID", | ||
| })("should return a specific product", async () => { | ||
| const response = await request(app).get("/api/products/1") | ||
|
|
||
| expect(response.status).toBe(200) | ||
| expect(response.body).toHaveProperty("id", 1) | ||
| expect(response.body).toHaveProperty("name", "Laptop") | ||
| expect(response.body).toHaveProperty("price", 999.99) | ||
| expect(response.body).toHaveProperty("category", "Electronics") | ||
| }) | ||
|
|
||
| apiTest("should return product with different ID", async () => { | ||
| const response = await request(app).get("/api/products/2") | ||
|
|
||
| expect(response.status).toBe(200) | ||
| expect(response.body).toHaveProperty("id", 2) | ||
| expect(response.body).toHaveProperty("name", "Phone") | ||
| }) | ||
| }) | ||
|
|
||
| describe("POST /api/products", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Create new product", | ||
| tags: ["Products", "Create"], | ||
| description: "Creates a new product with the provided information", | ||
| })("should create a new product", async () => { | ||
| const response = await request(app).post("/api/products").send({ | ||
| name: "Test Product", | ||
| price: 99.99, | ||
| category: "Test Category", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(201) | ||
| expect(response.body).toHaveProperty("id", 3) | ||
| expect(response.body).toHaveProperty("name", "Test Product") | ||
| expect(response.body).toHaveProperty("price", 99.99) | ||
| expect(response.body).toHaveProperty("category", "Test Category") | ||
| }) | ||
|
|
||
| apiTest.withMeta({ | ||
| summary: "Create product with different data", | ||
| tags: ["Products", "Create"], | ||
| })("should create another product", async () => { | ||
| const response = await request(app).post("/api/products").send({ | ||
| name: "Another Product", | ||
| price: 199.99, | ||
| category: "Another Category", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(201) | ||
| expect(response.body.name).toBe("Another Product") | ||
| }) | ||
| }) | ||
|
|
||
| describe("PUT /api/products/:id", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Update product", | ||
| tags: ["Products", "Update"], | ||
| description: "Updates an existing product with the provided information", | ||
| })("should update a product", async () => { | ||
| const response = await request(app).put("/api/products/1").send({ | ||
| name: "Updated Product", | ||
| price: 199.99, | ||
| category: "Updated Category", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(200) | ||
| expect(response.body).toHaveProperty("id", 1) | ||
| expect(response.body).toHaveProperty("name", "Updated Product") | ||
| expect(response.body).toHaveProperty("price", 199.99) | ||
| expect(response.body).toHaveProperty("category", "Updated Category") | ||
| }) | ||
|
|
||
| apiTest("should update product with partial data", async () => { | ||
| const response = await request(app).put("/api/products/2").send({ | ||
| name: "Partially Updated", | ||
| price: 299.99, | ||
| category: "Electronics", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(200) | ||
| expect(response.body.name).toBe("Partially Updated") | ||
| }) | ||
| }) | ||
|
|
||
| describe("DELETE /api/products/:id", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Delete product", | ||
| tags: ["Products", "Delete"], | ||
| description: "Deletes a product by its ID", | ||
| })("should delete a product", async () => { | ||
| const response = await request(app).delete("/api/products/1") | ||
|
|
||
| expect(response.status).toBe(204) | ||
| }) | ||
|
|
||
| apiTest("should delete another product", async () => { | ||
| const response = await request(app).delete("/api/products/2") | ||
|
|
||
| expect(response.status).toBe(204) | ||
| }) | ||
| }) | ||
|
|
||
| describe("Complete product CRUD workflow", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Product CRUD workflow", | ||
| tags: ["Products", "Workflow", "CRUD"], | ||
| description: "Complete create, read, update, delete workflow for products", | ||
| })("should perform complete CRUD operations", async () => { | ||
| // Step 1: Create a product | ||
| const createResponse = await request(app).post("/api/products").send({ | ||
| name: "Workflow Product", | ||
| price: 149.99, | ||
| category: "Test", | ||
| }) | ||
|
|
||
| expect(createResponse.status).toBe(201) | ||
| const productId = createResponse.body.id | ||
|
|
||
| // Step 2: Read the product | ||
| const getResponse = await request(app).get(`/api/products/${productId}`) | ||
|
|
||
| expect(getResponse.status).toBe(200) | ||
| expect(getResponse.body.name).toBe("Workflow Product") | ||
|
|
||
| // Step 3: Update the product | ||
| const updateResponse = await request(app).put(`/api/products/${productId}`).send({ | ||
| name: "Updated Workflow Product", | ||
| price: 179.99, | ||
| category: "Updated Test", | ||
| }) | ||
|
|
||
| expect(updateResponse.status).toBe(200) | ||
| expect(updateResponse.body.name).toBe("Updated Workflow Product") | ||
|
|
||
| // Step 4: Delete the product | ||
| const deleteResponse = await request(app).delete(`/api/products/${productId}`) | ||
|
|
||
| expect(deleteResponse.status).toBe(204) | ||
| }) | ||
| }) | ||
|
|
||
| describe("Product filtering and search", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Filter products by category", | ||
| tags: ["Products", "Filter"], | ||
| })("should filter products with query params", async () => { | ||
| const response = await request(app) | ||
| .get("/api/products/1") | ||
| .query({ category: "Electronics", minPrice: 500 }) | ||
|
|
||
| expect(response.status).toBe(200) | ||
| }) | ||
|
|
||
| apiTest("should search products with multiple params", async () => { | ||
| const response = await request(app).get("/api/products/1").query({ | ||
| search: "laptop", | ||
| sortBy: "price", | ||
| order: "asc", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(200) | ||
| }) | ||
|
json-choi marked this conversation as resolved.
Outdated
|
||
| }) | ||
|
|
||
| describe("Product API with authentication", () => { | ||
| apiTest.withMeta({ | ||
| summary: "Create product with auth", | ||
| tags: ["Products", "Authentication"], | ||
| })("should create product with authorization header", async () => { | ||
| const response = await request(app) | ||
| .post("/api/products") | ||
| .set("Authorization", "Bearer fake-token-123") | ||
| .send({ | ||
| name: "Authenticated Product", | ||
| price: 299.99, | ||
| category: "Secure", | ||
| }) | ||
|
|
||
| expect(response.status).toBe(201) | ||
| }) | ||
|
|
||
| apiTest("should include custom headers", async () => { | ||
| const response = await request(app) | ||
| .get("/api/products/1") | ||
| .set("Authorization", "Bearer token") | ||
| .set("X-Client-ID", "test-client") | ||
| .set("Accept", "application/json") | ||
|
|
||
| expect(response.status).toBe(200) | ||
| }) | ||
| }) | ||
| }) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.