-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from Vendic/fix/PIPE-268-fix-comments-with-wron…
…g-extracted-tickets PIPE-268 - Don't fail on clickup API call exceptions, and expose the tasks for which it failed.
- Loading branch information
Showing
5 changed files
with
346 additions
and
230 deletions.
There are no files selected for viewing
This file contains 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,59 +1,179 @@ | ||
import * as core from '@actions/core' | ||
import * as fs from "fs"; | ||
import nock from "nock"; | ||
import {expect, test} from '@jest/globals' | ||
import get_tasks from '../src/get_tasks' | ||
|
||
test('Test get 2 tasks from Clickup API', async () => { | ||
// Mocks | ||
const failed_mock = jest.spyOn(core, 'setFailed') | ||
const output_mock = jest.spyOn(core, 'setOutput') | ||
|
||
const get_reply = JSON.parse(fs.readFileSync(__dirname + '/' + 'get_response.json', 'utf-8')) | ||
nock('https://api.clickup.com') | ||
.persist() | ||
.get('/api/v2/task/ABC-185/?custom_task_ids=true&team_id=123') | ||
.reply(200, get_reply) | ||
nock('https://api.clickup.com') | ||
.persist() | ||
.get('/api/v2/task/DEF-186/?custom_task_ids=true&team_id=123') | ||
.reply(200, get_reply) | ||
|
||
await get_tasks() | ||
|
||
const expected_output = JSON.stringify([ | ||
{ | ||
"custom_id": "TEST123", | ||
"description": "Price isn't correct "displayed" in the rich snippets", | ||
"priority": { | ||
"color": "#d8d8d8", | ||
"id": "4", | ||
"orderindex": "4", | ||
"priority": "low" | ||
}, | ||
"url": "https://app.clickup.com/t/9hx" | ||
import * as core from '@actions/core'; | ||
import { expect, describe, it, beforeEach, jest } from '@jest/globals'; | ||
import get_tasks from '../src/get_tasks'; | ||
import { Task } from '../src/types'; | ||
import {getTask} from "../src/api_calls"; | ||
|
||
jest.mock('@actions/core'); | ||
jest.mock('../src/api_calls'); | ||
|
||
const mockedCore = core as jest.Mocked<typeof core>; | ||
const mockedGetTask = getTask as jest.MockedFunction<typeof getTask>; | ||
|
||
describe('get_tasks', () => { | ||
const defaultTaskIds = ['TASK-1', 'TASK-2', 'INVALID-TASK']; | ||
const defaultResponseFields = ['url', 'description', 'custom_id', 'priority']; | ||
const task1: Task = { | ||
url: 'https://app.clickup.com/t/TASK-1', | ||
description: 'Task "One" description', | ||
custom_id: 'TASK-1', | ||
priority: { | ||
color: '#ff0000', | ||
id: '1', | ||
orderindex: '1', | ||
priority: 'High', | ||
}, | ||
{ | ||
"custom_id": "TEST123", | ||
"description": "Price isn't correct "displayed" in the rich snippets", | ||
"priority": { | ||
"color": "#d8d8d8", | ||
"id": "4", | ||
"orderindex": "4", | ||
"priority": "low" | ||
}; | ||
const task2: Task = { | ||
url: 'https://app.clickup.com/t/TASK-2', | ||
description: "It's the second task", | ||
custom_id: 'TASK-2', | ||
priority: { | ||
color: '#00ff00', | ||
id: '2', | ||
orderindex: '2', | ||
priority: 'Normal', | ||
}, | ||
}; | ||
|
||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
|
||
// Mock core inputs | ||
mockedCore.getInput.mockImplementation((name: string) => { | ||
const inputs: Record<string, string> = { | ||
clickup_token: 'test_token', | ||
clickup_team_id: 'test_team_id', | ||
}; | ||
return inputs[name] || ''; | ||
}); | ||
|
||
mockedCore.getMultilineInput.mockImplementation((name: string) => { | ||
const multilineInputs: Record<string, string[]> = { | ||
clickup_custom_task_ids: defaultTaskIds, | ||
response_fields: defaultResponseFields, | ||
}; | ||
return multilineInputs[name] || []; | ||
}); | ||
|
||
mockedCore.getBooleanInput.mockImplementation((name: string) => { | ||
const booleanInputs: Record<string, boolean> = { | ||
convert_quotes: true, | ||
}; | ||
return booleanInputs[name] ?? true; | ||
}); | ||
|
||
// Mock core output functions | ||
jest.spyOn(mockedCore, 'setOutput'); | ||
jest.spyOn(mockedCore, 'setFailed'); | ||
jest.spyOn(mockedCore, 'info'); | ||
jest.spyOn(mockedCore, 'debug'); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('retrieves tasks and converts quotes when convert_quotes is true', async () => { | ||
// Arrange | ||
mockedGetTask.mockImplementation(async (taskId: string) => { | ||
if (taskId === 'TASK-1') return { ...task1 }; | ||
if (taskId === 'TASK-2') return { ...task2 }; | ||
const error = new Error('Task not found'); | ||
(error as any).response = { status: 404 }; | ||
throw error; | ||
}); | ||
|
||
const expectedTasks = [ | ||
{ | ||
...task1, | ||
description: 'Task "One" description', | ||
}, | ||
{ | ||
...task2, | ||
description: 'It's the second task', | ||
}, | ||
"url": "https://app.clickup.com/t/9hx" | ||
} | ||
]); | ||
|
||
expect(failed_mock).toHaveBeenCalledTimes(0) | ||
expect(output_mock).toHaveBeenCalledWith('clickup_tasks', expected_output) | ||
}) | ||
|
||
beforeEach(() => { | ||
process.env['INPUT_CLICKUP_TOKEN'] = 'pk_123' | ||
process.env['INPUT_RESPONSE_FIELDS'] = 'url\ndescription\ncustom_id\npriority' | ||
process.env['INPUT_CLICKUP_CUSTOM_TASK_IDS'] = 'ABC-185\nDEF-186' | ||
process.env['INPUT_CLICKUP_TEAM_ID'] = '123' | ||
process.env['INPUT_CONVERT_QUOTES'] = 'true' | ||
}) | ||
]; | ||
|
||
// Act | ||
await get_tasks(); | ||
|
||
// Assert | ||
expect(mockedGetTask).toHaveBeenCalledTimes(3); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('clickup_tasks', JSON.stringify(expectedTasks)); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('invalid_tasks', JSON.stringify(['INVALID-TASK'])); | ||
expect(mockedCore.setFailed).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('does not convert quotes when convert_quotes is false', async () => { | ||
// Arrange | ||
mockedCore.getBooleanInput.mockReturnValue(false); | ||
|
||
mockedGetTask.mockImplementation(async (taskId: string) => { | ||
if (taskId === 'TASK-1') return { ...task1 }; | ||
if (taskId === 'TASK-2') return { ...task2 }; | ||
const error = new Error('Task not found'); | ||
(error as any).response = { status: 404 }; | ||
throw error; | ||
}); | ||
|
||
const expectedTasks = [task1, task2]; | ||
|
||
// Act | ||
await get_tasks(); | ||
|
||
// Assert | ||
expect(mockedGetTask).toHaveBeenCalledTimes(3); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('clickup_tasks', JSON.stringify(expectedTasks)); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('invalid_tasks', JSON.stringify(['INVALID-TASK'])); | ||
expect(mockedCore.setFailed).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('handles empty task IDs gracefully', async () => { | ||
// Arrange | ||
mockedCore.getMultilineInput.mockImplementation((name: string) => { | ||
if (name === 'clickup_custom_task_ids') return []; | ||
return defaultResponseFields; | ||
}); | ||
|
||
// Act | ||
await get_tasks(); | ||
|
||
// Assert | ||
expect(mockedGetTask).not.toHaveBeenCalled(); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('clickup_tasks', JSON.stringify([])); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('invalid_tasks', JSON.stringify([])); | ||
expect(mockedCore.setFailed).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('collects invalid task IDs when getTask throws errors', async () => { | ||
// Arrange | ||
mockedGetTask.mockRejectedValue(new Error('Network Error')); | ||
|
||
// Act | ||
await get_tasks(); | ||
|
||
// Assert | ||
expect(mockedGetTask).toHaveBeenCalledTimes(3); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('clickup_tasks', JSON.stringify([])); | ||
expect(mockedCore.setOutput).toHaveBeenCalledWith('invalid_tasks', JSON.stringify(defaultTaskIds)); | ||
expect(mockedCore.setFailed).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('fails the action if an error occurs outside the loop', async () => { | ||
// Arrange | ||
mockedCore.getInput.mockImplementation((name: string) => { | ||
if (name === 'clickup_token') throw new Error('Input required and not supplied: clickup_token'); | ||
return ''; | ||
}); | ||
|
||
// Act | ||
await get_tasks(); | ||
|
||
// Assert | ||
expect(mockedCore.setFailed).toHaveBeenCalledWith( | ||
'Action failed: Error: Input required and not supplied: clickup_token' | ||
); | ||
expect(mockedCore.setOutput).not.toHaveBeenCalled(); | ||
}); | ||
}); |
This file contains 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
Oops, something went wrong.