worklog-adf-conversion.integration.test.ts•10.2 kB
/**
 * Worklog ADF Conversion Integration Test
 *
 * Tests the integration between worklog repository and ADF parser
 * to ensure comments are properly converted to ADF format before
 * being sent to JIRA API.
 */
import { describe, expect, it, jest, beforeEach } from "bun:test";
import type { HttpClient } from "@features/jira/client/http/jira.http.types";
import { WorklogRepositoryImpl } from "@features/jira/issues/repositories/worklog.repository";
import type { ADFDocument } from "@features/jira/shared/parsers/adf.parser";
describe("Worklog ADF Conversion Integration", () => {
  let repository: WorklogRepositoryImpl;
  let mockHttpClient: HttpClient;
  beforeEach(() => {
    mockHttpClient = {
      sendRequest: jest.fn(),
    } as unknown as HttpClient;
    repository = new WorklogRepositoryImpl(mockHttpClient);
  });
  describe("addWorklog ADF conversion", () => {
    it("should convert simple string comment to ADF format", async () => {
      // Arrange
      const issueKey = "TEST-123";
      const timeSpent = "2h";
      const comment = "Fixed authentication bug";
      const expectedADFComment: ADFDocument = {
        type: "doc",
        version: 1,
        content: [
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Fixed authentication bug",
              },
            ],
          },
        ],
      };
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "10001",
        timeSpent,
        comment: expectedADFComment,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog`,
        method: "POST",
        body: {
          timeSpent,
          comment: expectedADFComment,
        },
      });
    });
    it("should convert multiline comment to ADF with multiple paragraphs", async () => {
      // Arrange
      const issueKey = "TEST-456";
      const timeSpent = "3h";
      const comment =
        "Fixed authentication bug\n\nAlso updated documentation\n\nTested on staging";
      const expectedADFComment: ADFDocument = {
        type: "doc",
        version: 1,
        content: [
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Fixed authentication bug",
              },
            ],
          },
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Also updated documentation",
              },
            ],
          },
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Tested on staging",
              },
            ],
          },
        ],
      };
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "10002",
        timeSpent,
        comment: expectedADFComment,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog`,
        method: "POST",
        body: {
          timeSpent,
          comment: expectedADFComment,
        },
      });
    });
    it("should not include comment in body when comment is empty", async () => {
      // Arrange
      const issueKey = "TEST-789";
      const timeSpent = "1h";
      const comment = "";
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "10003",
        timeSpent,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog`,
        method: "POST",
        body: {
          timeSpent,
          // No comment field should be present
        },
      });
    });
    it("should not include comment in body when comment is undefined", async () => {
      // Arrange
      const issueKey = "TEST-101";
      const timeSpent = "30m";
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "10004",
        timeSpent,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, undefined);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog`,
        method: "POST",
        body: {
          timeSpent,
          // No comment field should be present
        },
      });
    });
  });
  describe("updateWorklog ADF conversion", () => {
    it("should convert string comment to ADF format when updating", async () => {
      // Arrange
      const issueKey = "TEST-UPDATE";
      const worklogId = "20001";
      const timeSpent = "4h";
      const comment = "Updated work description with more details";
      const expectedADFComment: ADFDocument = {
        type: "doc",
        version: 1,
        content: [
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Updated work description with more details",
              },
            ],
          },
        ],
      };
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: worklogId,
        timeSpent,
        comment: expectedADFComment,
      });
      // Act
      await repository.updateWorklog(issueKey, worklogId, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog/${worklogId}`,
        method: "PUT",
        body: {
          timeSpent,
          comment: expectedADFComment,
        },
      });
    });
    it("should handle complex comment with special characters", async () => {
      // Arrange
      const issueKey = "TEST-SPECIAL";
      const worklogId = "20002";
      const timeSpent = "2h 30m";
      const comment =
        "Fixed bug with special chars: @#$%^&*()_+{}|:<>?[]\\;',./`~";
      const expectedADFComment: ADFDocument = {
        type: "doc",
        version: 1,
        content: [
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Fixed bug with special chars: @#$%^&*()_+{}|:<>?[]\\;',./`~",
              },
            ],
          },
        ],
      };
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: worklogId,
        timeSpent,
        comment: expectedADFComment,
      });
      // Act
      await repository.updateWorklog(issueKey, worklogId, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog/${worklogId}`,
        method: "PUT",
        body: {
          timeSpent,
          comment: expectedADFComment,
        },
      });
    });
  });
  describe("real-world scenarios", () => {
    it("should handle typical development work log comment", async () => {
      // Arrange
      const issueKey = "PROJ-1234";
      const timeSpent = "5h 30m";
      const comment = `Implemented user authentication feature:
- Added login/logout functionality
- Integrated with OAuth provider
- Added session management
- Updated user interface
- Added unit tests
Tested on development environment and ready for review.`;
      const expectedADFComment: ADFDocument = {
        type: "doc",
        version: 1,
        content: [
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Implemented user authentication feature:",
              },
            ],
          },
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "- Added login/logout functionality\n- Integrated with OAuth provider\n- Added session management\n- Updated user interface\n- Added unit tests",
              },
            ],
          },
          {
            type: "paragraph",
            content: [
              {
                type: "text",
                text: "Tested on development environment and ready for review.",
              },
            ],
          },
        ],
      };
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "30001",
        timeSpent,
        comment: expectedADFComment,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, comment);
      // Assert
      expect(mockHttpClient.sendRequest).toHaveBeenCalledWith({
        endpoint: `issue/${issueKey}/worklog`,
        method: "POST",
        body: {
          timeSpent,
          comment: expectedADFComment,
        },
      });
    });
    it("should handle bug fix work log comment", async () => {
      // Arrange
      const issueKey = "BUG-567";
      const timeSpent = "2h 15m";
      const comment = `Fixed critical authentication bug:
Root cause: Session timeout not properly handled
Solution: Added proper session validation and refresh logic
Changes made:
- Updated session middleware
- Added error handling for expired sessions
- Improved user feedback for authentication failures
Verified fix works correctly in all browsers.`;
      (mockHttpClient.sendRequest as jest.Mock).mockResolvedValue({
        id: "30002",
        timeSpent,
      });
      // Act
      await repository.addWorklog(issueKey, timeSpent, comment);
      // Assert - Verify that the comment was converted to ADF format
      const callArgs = (mockHttpClient.sendRequest as jest.Mock).mock
        .calls[0][0];
      expect(callArgs.body.comment).toBeDefined();
      expect(callArgs.body.comment.type).toBe("doc");
      expect(callArgs.body.comment.version).toBe(1);
      expect(callArgs.body.comment.content).toBeArray();
      expect(callArgs.body.comment.content.length).toBeGreaterThan(1);
    });
  });
});