-
Notifications
You must be signed in to change notification settings - Fork 425
[jsweep] Clean update_handler_factory.cjs #39019
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -807,4 +807,133 @@ describe("update_handler_factory.cjs", () => { | |
| expect(mockCore.info).toHaveBeenCalledWith(expect.stringContaining('"body"')); | ||
| }); | ||
| }); | ||
|
|
||
| describe("handler control flow", () => { | ||
| it("should return staged result when config.staged is true", async () => { | ||
| const mockExecuteUpdate = vi.fn(); | ||
|
|
||
| const handlerFactory = factoryModule.createUpdateHandlerFactory({ | ||
| itemType: "update_test", | ||
|
Comment on lines
+812
to
+816
|
||
| itemTypeName: "test item", | ||
| supportsPR: false, | ||
| resolveItemNumber: vi.fn().mockReturnValue({ success: true, number: 42 }), | ||
| buildUpdateData: vi.fn().mockReturnValue({ success: true, data: { title: "New title" } }), | ||
| executeUpdate: mockExecuteUpdate, | ||
| formatSuccessResult: vi.fn().mockReturnValue({ success: true }), | ||
| }); | ||
|
|
||
| const handler = await handlerFactory({ staged: true }); | ||
| const result = await handler({ title: "New title" }); | ||
|
|
||
| expect(result.success).toBe(true); | ||
| expect(result.staged).toBe(true); | ||
| expect(result.previewInfo).toMatchObject({ number: 42 }); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Staged-mode preview assertions are incomplete — future regressions in what the staged payload captures will not be detected. 💡 Suggested additionsThe staged path returns Consider adding: expect(result.previewInfo.updateFields).toEqual(["title"]);
expect(result.previewInfo.hasRawBody).toBe(false);
// optionally: formatSuccessResult not called in staged mode
expect(handlerConfig.formatSuccessResult).not.toHaveBeenCalled();The |
||
| // executeUpdate must NOT be called in staged mode | ||
| expect(mockExecuteUpdate).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("should return skipped result when buildUpdateData returns skipped:true", async () => { | ||
| const mockExecuteUpdate = vi.fn(); | ||
|
|
||
| const handlerFactory = factoryModule.createUpdateHandlerFactory({ | ||
| itemType: "update_test", | ||
| itemTypeName: "test item", | ||
| supportsPR: false, | ||
| resolveItemNumber: vi.fn().mockReturnValue({ success: true, number: 42 }), | ||
| buildUpdateData: vi.fn().mockReturnValue({ | ||
| success: true, | ||
| skipped: true, | ||
| reason: "No supported fields provided", | ||
| }), | ||
| executeUpdate: mockExecuteUpdate, | ||
| formatSuccessResult: vi.fn().mockReturnValue({ success: true }), | ||
| }); | ||
|
|
||
| const handler = await handlerFactory({}); | ||
| const result = await handler({ title: "Test" }); | ||
|
|
||
| expect(result.success).toBe(true); | ||
| expect(result.skipped).toBe(true); | ||
| expect(result.reason).toBe("No supported fields provided"); | ||
| expect(mockExecuteUpdate).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("should propagate deferred flag from resolveItemNumber", async () => { | ||
| const mockExecuteUpdate = vi.fn(); | ||
|
|
||
| const handlerFactory = factoryModule.createUpdateHandlerFactory({ | ||
| itemType: "update_test", | ||
| itemTypeName: "test item", | ||
| supportsPR: false, | ||
| resolveItemNumber: vi.fn().mockReturnValue({ | ||
| success: false, | ||
| deferred: true, | ||
| error: "Temporary ID not yet resolved: aw_pending", | ||
| }), | ||
| buildUpdateData: vi.fn(), | ||
| executeUpdate: mockExecuteUpdate, | ||
| formatSuccessResult: vi.fn(), | ||
| }); | ||
|
|
||
| const handler = await handlerFactory({}); | ||
| const result = await handler({ issue_number: "aw_pending" }); | ||
|
|
||
| expect(result.success).toBe(false); | ||
| expect(result.deferred).toBe(true); | ||
| expect(result.error).toContain("aw_pending"); | ||
| expect(mockExecuteUpdate).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("should call itemFilter and skip update when filter returns a result", async () => { | ||
| const mockExecuteUpdate = vi.fn(); | ||
| const mockItemFilter = vi.fn().mockResolvedValue({ | ||
| success: false, | ||
| skipped: true, | ||
| error: "Required label not present", | ||
| }); | ||
|
|
||
| const handlerFactory = factoryModule.createUpdateHandlerFactory({ | ||
| itemType: "update_test", | ||
| itemTypeName: "test item", | ||
| supportsPR: false, | ||
| resolveItemNumber: vi.fn().mockReturnValue({ success: true, number: 42 }), | ||
| buildUpdateData: vi.fn().mockReturnValue({ success: true, data: { title: "Test" } }), | ||
| executeUpdate: mockExecuteUpdate, | ||
| formatSuccessResult: vi.fn().mockReturnValue({ success: true }), | ||
| itemFilter: mockItemFilter, | ||
| }); | ||
|
|
||
| const handler = await handlerFactory({}); | ||
| const result = await handler({ title: "Test" }); | ||
|
|
||
| expect(mockItemFilter).toHaveBeenCalled(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When |
||
| expect(result.success).toBe(false); | ||
| expect(result.skipped).toBe(true); | ||
| expect(result.error).toBe("Required label not present"); | ||
| expect(mockExecuteUpdate).not.toHaveBeenCalled(); | ||
|
Copilot marked this conversation as resolved.
|
||
| }); | ||
|
|
||
| it("should call itemFilter and proceed when filter returns null", async () => { | ||
| const mockExecuteUpdate = vi.fn().mockResolvedValue({ html_url: "https://example.com", title: "Updated" }); | ||
| const mockItemFilter = vi.fn().mockResolvedValue(null); | ||
|
|
||
| const handlerFactory = factoryModule.createUpdateHandlerFactory({ | ||
| itemType: "update_test", | ||
| itemTypeName: "test item", | ||
| supportsPR: false, | ||
| resolveItemNumber: vi.fn().mockReturnValue({ success: true, number: 42 }), | ||
| buildUpdateData: vi.fn().mockReturnValue({ success: true, data: { title: "Test" } }), | ||
| executeUpdate: mockExecuteUpdate, | ||
| formatSuccessResult: vi.fn().mockReturnValue({ success: true }), | ||
| itemFilter: mockItemFilter, | ||
| }); | ||
|
|
||
| const handler = await handlerFactory({}); | ||
| const result = await handler({ title: "Test" }); | ||
|
|
||
| expect(mockItemFilter).toHaveBeenCalled(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both Production code calls expect(mockItemFilter).toHaveBeenCalledWith(
expect.anything(), // githubClient
{ owner: 'testowner', repo: 'testrepo' },
42, // itemNumber
expect.objectContaining({}) // config
);Without this, a cross-repo routing bug that passes the wrong |
||
| expect(result.success).toBe(true); | ||
| expect(mockExecuteUpdate).toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additionalConfigvalues are silently ignored — only its keys are used as a whitelist — the refactored form makes this harder to notice.Both old and new code read
config[key](runtime value) for the log entry, notadditionalConfig[key](schema value). The old code made this slightly visible via the unusedvaluedestructure variable; the new compact form hides it entirely.If a future contributor adds a value to
additionalConfigexpecting it to appear in the log (e.g., as a default or label), it will be silently ignored. Consider a short comment to document intent: