Skip to content
Closed
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"test:commands": "tsx tests/command-coverage.ts",
"prepare": "npm_config_global=false npm install --ignore-scripts && tsc && chmod +x dist/main.js",
"prepublishOnly": "npm run build && npm run test && test -x dist/main.js"
},
"engines": {
Expand Down
10 changes: 6 additions & 4 deletions src/utils/graphql-issues-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -881,10 +881,12 @@ export class GraphQLIssuesService {
id: comment.id,
body: comment.body,
embeds: extractEmbeds(comment.body),
user: {
id: comment.user.id,
name: comment.user.name,
},
user: comment.user
? {
id: comment.user.id,
name: comment.user.name,
}
: undefined,
createdAt: comment.createdAt instanceof Date
? comment.createdAt.toISOString()
: (comment.createdAt
Expand Down
4 changes: 2 additions & 2 deletions src/utils/linear-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export interface LinearIssue {
url: string;
expiresAt: string;
}>;
user: {
user?: {
id: string;
name: string;
};
Expand Down Expand Up @@ -153,7 +153,7 @@ export interface CreateCommentArgs {
export interface LinearComment {
id: string;
body: string;
user: {
user?: {
id: string;
name: string;
};
Expand Down
92 changes: 92 additions & 0 deletions tests/unit/graphql-issues-service-null-comment-user.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { GraphQLIssuesService } from "../../src/utils/graphql-issues-service.js";
import type { GraphQLService } from "../../src/utils/graphql-service.js";

/**
* Unit tests for null comment.user handling in doTransformIssueData.
*
* When a Linear issue has automated/synced comments (e.g. from GitHub
* integration), the `user` field on the comment can be `null`.
* Previously this caused: Cannot read properties of null (reading 'id').
*/

function makeIssueResponse(commentOverrides: Record<string, unknown> = {}) {
return {
issue: {
id: "issue-1",
identifier: "ENG-100",
title: "Test Issue",
description: null,
branchName: null,
priority: 0,
estimate: null,
state: { id: "state-1", name: "In Progress" },
assignee: null,
team: { id: "team-1", key: "ENG", name: "Engineering" },
project: null,
cycle: null,
projectMilestone: null,
labels: { nodes: [] },
parent: null,
children: { nodes: [] },
comments: {
nodes: [
{
id: "comment-1",
body: "Automated sync comment",
user: null,
createdAt: "2025-01-01T00:00:00Z",
updatedAt: "2025-01-01T00:00:00Z",
...commentOverrides,
},
],
},
createdAt: "2025-01-01T00:00:00Z",
updatedAt: "2025-01-01T00:00:00Z",
},
};
}

describe("GraphQLIssuesService - Null Comment User", () => {
let mockGraphQLService: { rawRequest: ReturnType<typeof vi.fn> };
let service: GraphQLIssuesService;

beforeEach(() => {
mockGraphQLService = {
rawRequest: vi.fn(),
};
service = new GraphQLIssuesService(
mockGraphQLService as unknown as GraphQLService,
);
});

it("should handle comment with null user without crashing", async () => {
mockGraphQLService.rawRequest.mockResolvedValue(makeIssueResponse());

const result = await service.getIssueById(
"550e8400-e29b-41d4-a716-446655440000",
);

expect(result.comments).toHaveLength(1);
expect(result.comments![0].user).toBeUndefined();
expect(result.comments![0].body).toBe("Automated sync comment");
});

it("should preserve user when present on comment", async () => {
mockGraphQLService.rawRequest.mockResolvedValue(
makeIssueResponse({
user: { id: "user-1", name: "Alice" },
}),
);

const result = await service.getIssueById(
"550e8400-e29b-41d4-a716-446655440000",
);

expect(result.comments).toHaveLength(1);
expect(result.comments![0].user).toEqual({
id: "user-1",
name: "Alice",
});
});
});