Skip to content

Commit

Permalink
adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
karpikpl committed Apr 30, 2024
1 parent 0e54cca commit e52c38c
Show file tree
Hide file tree
Showing 13 changed files with 433 additions and 110 deletions.
166 changes: 148 additions & 18 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
*/

import * as core from '@actions/core'
import * as github from '@actions/github'
import * as main from '../src/main'
import { Octokit } from "@octokit/rest";

Check failure on line 12 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Replace `"@octokit/rest";` with `'@octokit/rest'`

Check failure on line 12 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Extra semicolon
import { mockInputs } from './mock.helper'
import * as azdo from '../src/azdo'
import { WorkItemsBatchResponse } from '../src/azdoTypes'
import fs from 'fs';

Check failure on line 16 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Delete `;`

Check failure on line 16 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Extra semicolon
import path from 'path';

Check failure on line 17 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Delete `;`

Check failure on line 17 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Extra semicolon

// Mock the action's main function
const runMock = jest.spyOn(main, 'run')
Expand All @@ -21,55 +28,178 @@ let errorMock: jest.SpiedFunction<typeof core.error>
let getInputMock: jest.SpiedFunction<typeof core.getInput>
let setFailedMock: jest.SpiedFunction<typeof core.setFailed>
let setOutputMock: jest.SpiedFunction<typeof core.setOutput>
let githubApi: Octokit
let getReleaseMock: jest.SpyInstance
let updateReleaseMock: jest.SpyInstance
let getOctokitMock: jest.SpyInstance

Check failure on line 34 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

'getOctokitMock' is assigned a value but never used
let getWorkItemsBatchMock: jest.SpiedFunction<typeof azdo.getWorkItemsBatch>

describe('action', () => {
beforeEach(() => {
jest.clearAllMocks()
githubApi = new Octokit()

debugMock = jest.spyOn(core, 'debug').mockImplementation()
errorMock = jest.spyOn(core, 'error').mockImplementation()
getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
setFailedMock = jest.spyOn(core, 'setFailed').mockImplementation()
setOutputMock = jest.spyOn(core, 'setOutput').mockImplementation()

getReleaseMock = jest.spyOn(githubApi.rest.repos, 'getRelease').mockImplementation()

Check failure on line 48 in __tests__/main.test.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Replace `.spyOn(githubApi.rest.repos,·'getRelease')` with `⏎······.spyOn(githubApi.rest.repos,·'getRelease')⏎······`
updateReleaseMock = jest.spyOn(githubApi.rest.repos, 'updateRelease').mockImplementation()
getOctokitMock = jest.spyOn(github, 'getOctokit').mockImplementation().mockReturnValue(githubApi)

getWorkItemsBatchMock = jest.spyOn(azdo, 'getWorkItemsBatch').mockImplementation()
})

it('sets the time output', async () => {
it('Gets release notes - no AB#', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
return '500'
default:
return ''
getInputMock = mockInputs();
getReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: 'This is a release note'
}
})

await main.run()
expect(runMock).toHaveReturned()

// Verify that all of the core library functions were called correctly
expect(debugMock).toHaveBeenNthCalledWith(1, 'Waiting 500 milliseconds ...')
expect(debugMock).toHaveBeenNthCalledWith(
2,
expect.stringMatching(timeRegex)
expect(setOutputMock).toHaveBeenNthCalledWith(
1,
'workItems',
''
)
expect(debugMock).toHaveBeenNthCalledWith(
3,
expect.stringMatching(timeRegex)
expect(errorMock).not.toHaveBeenCalled()
expect(setFailedMock).not.toHaveBeenCalled()
})

it('Fails when workitems could not be found in ADO', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock = mockInputs();
getReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: '# Release notes title\n\n - This is a release note\n - AB#1234'
}
})
getWorkItemsBatchMock.mockResolvedValueOnce(undefined)

await main.run()
expect(runMock).toHaveReturned()

// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenCalledWith('Failed to get work item details')
})

it('Updates release notes with work items from ADO', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock = mockInputs();
getReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: '# Release notes title\n\n - This is a release note\n - AB#1234'
}
})
updateReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: 'new body'
}
})
const workItemsBatchResponse : WorkItemsBatchResponse = {
count: 1,
value: [
{
id: 1234,
url: 'https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1234',
fields: {
'System.Id': 1234,
'System.Title': 'Work item title',
'System.WorkItemType': 'Task',
'System.State': 'Done',
}
}
]
}
getWorkItemsBatchMock.mockResolvedValueOnce(workItemsBatchResponse)

await main.run()
expect(runMock).toHaveReturned()

// Verify that all of the core library functions were called correctly
expect(setFailedMock).not.toHaveBeenCalled()
expect(setOutputMock).toHaveBeenNthCalledWith(
1,
'workItems',
'1234'
)
})

it('Updates release notes for many workitem references', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock = mockInputs();
const notesBefore = fs.readFileSync(path.join(__dirname, 'test_cases/big', 'notes_before.md'), 'utf8')
const notesAfter = fs.readFileSync(path.join(__dirname, 'test_cases/big', 'notes_after.md'), 'utf8')
const adoResponse = fs.readFileSync(path.join(__dirname, 'test_cases/big', 'ado_response.json'), 'utf8')
getReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: notesBefore
}
})
updateReleaseMock.mockResolvedValueOnce({
status: 200,
data: {
body: 'new body'
}
})
const workItemsBatchResponse : WorkItemsBatchResponse = JSON.parse(adoResponse)
getWorkItemsBatchMock.mockResolvedValueOnce(workItemsBatchResponse)

await main.run()
expect(runMock).toHaveReturned()

// Verify that all of the core library functions were called correctly
expect(setFailedMock).not.toHaveBeenCalled()
expect(setOutputMock).toHaveBeenNthCalledWith(
1,
'time',
expect.stringMatching(timeRegex)
'workItems',
'11, 1, 111, 5, 14, 143, 112'
)
expect(updateReleaseMock).toHaveBeenCalledWith({
owner: 'repoOwner',
repo: 'repoName',
release_id: 123,
body: notesAfter
})
})

it.each([
['', 'adoProject', 'adoOrg', 'token', 'repo_owner', 'repo_name'],
['adoPat', '', 'adoOrg', 'token', 'repo_owner', 'repo_name'],
['adoPat', 'adoProject', '', 'token', 'repo_owner', 'repo_name'],
['adoPat', 'adoProject', 'adoOrg', '', 'repo_owner', 'repo_name'],
['adoPat', 'adoProject', 'adoOrg', 'token', '', 'repo_name'],
['adoPat', 'adoProject', 'adoOrg', 'token', 'repo_owner', ''],
])('missing inputs: adoPat:"%s" adoProject:"%s" adoOrg:"%s" token:"%s" repoOwner:"%s" repoName:"%s"', async (adoPat, adoProject, adoOrg, token, repo_owner, repo_name) => {
// Set the action's inputs as return values from core.getInput()
getInputMock = mockInputs(123, adoPat, adoProject, adoOrg, token, repo_owner, repo_name)

await main.run()
expect(runMock).toHaveReturned()

// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(1, 'Missing required inputs')
expect(errorMock).not.toHaveBeenCalled()
})

it('sets a failed status', async () => {
// Set the action's inputs as return values from core.getInput()
getInputMock.mockImplementation(name => {
switch (name) {
case 'milliseconds':
case 'release-id':
return 'this is not a number'
default:
return ''
Expand All @@ -82,7 +212,7 @@ describe('action', () => {
// Verify that all of the core library functions were called correctly
expect(setFailedMock).toHaveBeenNthCalledWith(
1,
'milliseconds not a number'
'No release id provided'
)
expect(errorMock).not.toHaveBeenCalled()
})
Expand Down
44 changes: 44 additions & 0 deletions __tests__/mock.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as core from '@actions/core'

/**
* Mocks the core.getInput function with predefined values for testing purposes.
* @param releaseId - The release ID.
* @param adoPat - The ADO PAT (Personal Access Token).
* @param adoProject - The ADO project name.
* @param adoOrg - The ADO organization name.
* @param token - The repository token.
* @param repo_owner - The repository owner.
* @param repo_name - The repository name.
* @returns A jest.SpiedFunction representing the mocked core.getInput function.
*/
export function mockInputs(
releaseId: number = 123,
adoPat: string = 'pat',
adoProject: string = 'adoProject',
adoOrg: string = 'adoOrg',
token: string = 'token',
repo_owner: string = 'repoOwner',
repo_name: string = 'repoName'): jest.SpiedFunction<typeof core.getInput> {
const getInputMock = jest.spyOn(core, 'getInput').mockImplementation()
getInputMock.mockImplementation(name => {
switch (name) {
case 'ado-pat':
return adoPat
case 'ado-project':
return adoProject
case 'ado-org':
return adoOrg
case 'repo-token':
return token
case 'repo-owner':
return repo_owner
case 'repo-name':
return repo_name
case 'release-id':
return releaseId.toString()
default:
throw 'Unexpected input name'
}
})
return getInputMock
}
75 changes: 75 additions & 0 deletions __tests__/test_cases/big/ado_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"count": 6,
"value": [
{
"id": 1,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1",
"fields": {
"System.Id": 1,
"System.Title": "Work item 1",
"System.WorkItemType": "Task",
"System.State": "To Do"
}
},
{
"id": 11,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/11",
"fields": {
"System.Id": 11,
"System.Title": "Best Feature so far",
"System.WorkItemType": "User Story",
"System.State": "Completed"
}
},
{
"id": 111,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/111",
"fields": {
"System.Id": 111,
"System.Title": "Work item 111",
"System.WorkItemType": "Bug",
"System.State": "Active"
}
},
{
"id": 5,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/5",
"fields": {
"System.Id": 5,
"System.Title": "Work item 5",
"System.WorkItemType": "User Story",
"System.State": "In Progress"
}
},
{
"id": 14,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/14",
"fields": {
"System.Id": 14,
"System.Title": "Work item 14",
"System.WorkItemType": "Task",
"System.State": "Done"
}
},
{
"id": 143,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/143",
"fields": {
"System.Id": 143,
"System.Title": "Work item 143",
"System.WorkItemType": "Bug",
"System.State": "Closed"
}
},
{
"id": 112,
"url": "https://dev.azure.com/adoOrg/adoProject/_workitems/edit/112",
"fields": {
"System.Id": 112,
"System.Title": "Work item for working",
"System.WorkItemType": "User Story",
"System.State": "New"
}
}
]
}
17 changes: 17 additions & 0 deletions __tests__/test_cases/big/notes_after.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Release 1.0.0

## What's Changed

* [AB#11 [User Story] Best Feature so far (Completed)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/11) Feature/adding ci by @karpikpl in https://github.com/repoOwner/repoName/pull/1
* test [AB#1 [Task] Work item 1 (To Do)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1) by @karpikpl in https://github.com/repoOwner/repoName/pull/2
* test [AB#111 [Bug] Work item 111 (Active)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/111) 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/3
* Feature #[AB#5 [User Story] Work item 5 (In Progress)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/5)# by @karpikpl in https://github.com/repoOwner/repoName/pull/4
* Feature [AB#14 [Task] Work item 14 (Done)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/14) by @karpikpl in https://github.com/repoOwner/repoName/pull/5
* [AB#143 [Bug] Work item 143 (Closed)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/143) Feature 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/7
* [AB#112 [User Story] Work item for working (New)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/112)Feature by @karpikpl in https://github.com/repoOwner/repoName/pull/8

## New Contributors

* @karpikpl made their first contribution in https://github.com/repoOwner/repoName/pull/1

**Full Changelog**: https://github.com/repoOwner/repoName/commits/v0.0.1
17 changes: 17 additions & 0 deletions __tests__/test_cases/big/notes_before.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Release 1.0.0

## What's Changed

* AB#11 Feature/adding ci by @karpikpl in https://github.com/repoOwner/repoName/pull/1
* test AB#1 by @karpikpl in https://github.com/repoOwner/repoName/pull/2
* test AB#111 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/3
* Feature #AB#5# by @karpikpl in https://github.com/repoOwner/repoName/pull/4
* Feature AB#14 by @karpikpl in https://github.com/repoOwner/repoName/pull/5
* AB#143 Feature 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/7
* AB#112Feature by @karpikpl in https://github.com/repoOwner/repoName/pull/8

## New Contributors

* @karpikpl made their first contribution in https://github.com/repoOwner/repoName/pull/1

**Full Changelog**: https://github.com/repoOwner/repoName/commits/v0.0.1
11 changes: 11 additions & 0 deletions __tests__/test_cases/big/test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Release 1.0.0

## What's Changed

* [AB#11 [User Story] Best Feature so far (Completed)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/11) Feature/adding ci by @karpikpl in https://github.com/repoOwner/repoName/pull/1
* test [AB#1 [Task] Work item 1 (To Do)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1) by @karpikpl in https://github.com/repoOwner/repoName/pull/2
* test [AB#11 [User Story] Best Feature so far (Completed)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/11)1 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/3
* Feature #[AB#5 [User Story] Work item 5 (In Progress)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/5)# by @karpikpl in https://github.com/repoOwner/repoName/pull/4
* Feature [AB#1 [Task] Work item 1 (To Do)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1)4 by @karpikpl in https://github.com/repoOwner/repoName/pull/5
* [AB#1 [Task] Work item 1 (To Do)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/1)43 Feature 2 by @karpikpl in https://github.com/repoOwner/repoName/pull/7
* [AB#11 [User Story] Best Feature so far (Completed)](https://dev.azure.com/adoOrg/adoProject/_workitems/edit/11)2Feature by @karpikpl in https://github.com/repoOwner/repoName/pull/8
Loading

0 comments on commit e52c38c

Please sign in to comment.