- Add comprehensive router tests (26 tests) - Fix label/status routing priority - Add input validation for security - Optimize routing with Set-based lookups - Add markdown sanitization for Gitea output
204 lines
6.4 KiB
TypeScript
204 lines
6.4 KiB
TypeScript
import { describe, it, expect, beforeEach, mock } from "bun:test"
|
|
import { GiteaClient, type GiteaConfig } from "./gitea-client"
|
|
|
|
// Mock fetch for testing Gitea API interactions
|
|
declare global {
|
|
var fetch: any
|
|
}
|
|
|
|
describe("Gitea Client", () => {
|
|
let client: GiteaClient
|
|
let mockFetch: any
|
|
|
|
beforeEach(() => {
|
|
// Setup mock for fetch
|
|
mockFetch = mock(() => Promise.resolve({
|
|
ok: true,
|
|
status: 200,
|
|
json: () => Promise.resolve({}),
|
|
text: () => Promise.resolve("")
|
|
}))
|
|
globalThis.fetch = mockFetch
|
|
|
|
// Create client instance
|
|
client = new GiteaClient({
|
|
apiUrl: "https://git.softuniq.eu/api/v1",
|
|
token: "test-token",
|
|
owner: "test-owner",
|
|
repo: "test-repo"
|
|
})
|
|
})
|
|
|
|
describe("createMilestone", () => {
|
|
it("should create a milestone via Gitea API", async () => {
|
|
// This test will fail initially because we haven't actually implemented the API call yet
|
|
const milestoneData = {
|
|
title: "Test Milestone",
|
|
description: "A test milestone for validation",
|
|
state: "open" as const
|
|
}
|
|
|
|
// Mock expected response
|
|
mockFetch.mockResolvedValueOnce({
|
|
ok: true,
|
|
status: 201,
|
|
json: () => Promise.resolve({
|
|
id: 1,
|
|
...milestoneData,
|
|
open_issues: 0,
|
|
closed_issues: 0,
|
|
created_at: new Date().toISOString()
|
|
})
|
|
})
|
|
|
|
const result = await client.createMilestone(milestoneData)
|
|
|
|
// These assertions will fail until the actual implementation is done
|
|
expect(result.title).toBe("Test Milestone")
|
|
expect(result.state).toBe("open")
|
|
expect(result.id).toBe(1)
|
|
|
|
// Verify API call was made
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"https://git.softuniq.eu/api/v1/repos/test-owner/test-repo/milestones",
|
|
expect.objectContaining({
|
|
method: "POST",
|
|
headers: expect.objectContaining({
|
|
"Authorization": "token test-token"
|
|
})
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should handle API errors when creating milestone", async () => {
|
|
// This test will fail initially because error handling isn't properly implemented yet
|
|
mockFetch.mockResolvedValueOnce({
|
|
ok: false,
|
|
status: 401,
|
|
text: () => Promise.resolve("Unauthorized")
|
|
})
|
|
|
|
// This assertion will fail until error handling is properly implemented
|
|
await expect(client.createMilestone({ title: "Test" })).rejects.toThrow("Gitea API error")
|
|
})
|
|
})
|
|
|
|
describe("createIssue", () => {
|
|
it("should create an issue via Gitea API", async () => {
|
|
// This test will fail initially because we haven't actually implemented the API call yet
|
|
const issueData = {
|
|
title: "Test Issue",
|
|
body: "A test issue for validation",
|
|
labels: ["bug"]
|
|
}
|
|
|
|
// Mock expected response
|
|
mockFetch.mockResolvedValueOnce({
|
|
ok: true,
|
|
status: 201,
|
|
json: () => Promise.resolve({
|
|
id: 1,
|
|
number: 123,
|
|
...issueData,
|
|
state: "open",
|
|
comments: 0,
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString()
|
|
})
|
|
})
|
|
|
|
const result = await client.createIssue(issueData)
|
|
|
|
// These assertions will fail until the actual implementation is done
|
|
expect(result.title).toBe("Test Issue")
|
|
expect(result.number).toBe(123)
|
|
expect(result.state).toBe("open")
|
|
|
|
// Verify API call was made
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"https://git.softuniq.eu/api/v1/repos/test-owner/test-repo/issues",
|
|
expect.objectContaining({
|
|
method: "POST",
|
|
headers: expect.objectContaining({
|
|
"Authorization": "token test-token"
|
|
})
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("addComment", () => {
|
|
it("should add a comment to an issue via Gitea API", async () => {
|
|
// This test will fail initially because we haven't actually implemented the API call yet
|
|
const commentData = {
|
|
body: "## Test Comment\n\nThis is a test comment for validation"
|
|
}
|
|
|
|
// Mock expected response
|
|
mockFetch.mockResolvedValueOnce({
|
|
ok: true,
|
|
status: 201,
|
|
json: () => Promise.resolve({
|
|
id: 1,
|
|
...commentData,
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString()
|
|
})
|
|
})
|
|
|
|
const result = await client.createComment(123, commentData)
|
|
|
|
// These assertions will fail until the actual implementation is done
|
|
expect(result.body).toBe("## Test Comment\n\nThis is a test comment for validation")
|
|
expect(result.id).toBe(1)
|
|
|
|
// Verify API call was made
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"https://git.softuniq.eu/api/v1/repos/test-owner/test-repo/issues/123/comments",
|
|
expect.objectContaining({
|
|
method: "POST",
|
|
headers: expect.objectContaining({
|
|
"Authorization": "token test-token"
|
|
})
|
|
})
|
|
)
|
|
})
|
|
})
|
|
|
|
describe("setScopedStatus", () => {
|
|
it("should set a status label via Gitea API", async () => {
|
|
// This test will fail initially because we haven't actually implemented the label handling yet
|
|
|
|
// Mock sequence of API calls for removing old labels and adding new one
|
|
mockFetch
|
|
.mockResolvedValueOnce({ // getIssueLabels
|
|
ok: true,
|
|
status: 200,
|
|
json: () => Promise.resolve([{ id: 1, name: "status::new" }])
|
|
})
|
|
.mockResolvedValueOnce({ // removeLabel
|
|
ok: true,
|
|
status: 204,
|
|
json: () => Promise.resolve({})
|
|
})
|
|
.mockResolvedValueOnce({ // getRepoLabels
|
|
ok: true,
|
|
status: 200,
|
|
json: () => Promise.resolve([{ id: 2, name: "status::testing" }])
|
|
})
|
|
.mockResolvedValueOnce({ // addLabels
|
|
ok: true,
|
|
status: 200,
|
|
json: () => Promise.resolve([{ id: 2, name: "status::testing" }])
|
|
})
|
|
|
|
const result = await client.setScopedStatus(123, "testing")
|
|
|
|
// These assertions will fail until the actual implementation is done
|
|
expect(result[0].name).toBe("status::testing")
|
|
|
|
// Verify API calls were made in correct sequence
|
|
expect(mockFetch).toHaveBeenCalledTimes(4)
|
|
})
|
|
})
|
|
}) |