mirror of
https://github.com/actions/add-to-project.git
synced 2025-12-11 20:47:05 +00:00
Merge pull request #42 from actions/improve-test-coverage
Improves test coverage
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as github from '@actions/github'
|
||||
import {addToProject} from '../src/add-to-project'
|
||||
import {addToProject, mustGetOwnerTypeQuery} from '../src/add-to-project'
|
||||
|
||||
describe('addToProject', () => {
|
||||
let outputs: Record<string, string>
|
||||
@@ -94,6 +94,49 @@ describe('addToProject', () => {
|
||||
expect(outputs.itemId).toEqual('project-next-item-id')
|
||||
})
|
||||
|
||||
test('adds matching pull-requests with a label filter without label-operator', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'bug, new'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
// eslint-disable-next-line camelcase
|
||||
pull_request: {
|
||||
number: 1,
|
||||
labels: [{name: 'bug'}]
|
||||
}
|
||||
}
|
||||
|
||||
mockGraphQL(
|
||||
{
|
||||
test: /getProject/,
|
||||
return: {
|
||||
organization: {
|
||||
projectNext: {
|
||||
id: 'project-next-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /addProjectNextItem/,
|
||||
return: {
|
||||
addProjectNextItem: {
|
||||
projectNextItem: {
|
||||
id: 'project-next-item-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await addToProject()
|
||||
|
||||
expect(outputs.itemId).toEqual('project-next-item-id')
|
||||
})
|
||||
|
||||
test('does not add un-matching issues with a label filter without label-operator', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
@@ -179,6 +222,276 @@ describe('addToProject', () => {
|
||||
expect(infoSpy).toHaveBeenCalledWith(`Skipping issue 1 because it doesn't match all the labels: bug, new`)
|
||||
expect(gqlMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('adds matching issues with multiple label filters', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'accessibility,backend,bug'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: [{name: 'accessibility'}, {name: 'backend'}]
|
||||
}
|
||||
}
|
||||
|
||||
const gqlMock = mockGraphQL(
|
||||
{
|
||||
test: /getProject/,
|
||||
return: {
|
||||
organization: {
|
||||
projectNext: {
|
||||
id: 'project-next-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /addProjectNextItem/,
|
||||
return: {
|
||||
addProjectNextItem: {
|
||||
projectNextItem: {
|
||||
id: 'project-next-item-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const infoSpy = jest.spyOn(core, 'info')
|
||||
|
||||
await addToProject()
|
||||
|
||||
expect(gqlMock).toHaveBeenCalled()
|
||||
expect(infoSpy).not.toHaveBeenCalled()
|
||||
expect(outputs.itemId).toEqual('project-next-item-id')
|
||||
})
|
||||
|
||||
test('does not add un-matching issues with multiple label filters', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'accessibility, backend, bug'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: [{name: 'data'}, {name: 'frontend'}, {name: 'improvement'}]
|
||||
}
|
||||
}
|
||||
|
||||
const infoSpy = jest.spyOn(core, 'info')
|
||||
const gqlMock = mockGraphQL()
|
||||
await addToProject()
|
||||
expect(infoSpy).toHaveBeenCalledWith(
|
||||
`Skipping issue 1 because it does not have one of the labels: accessibility, backend, bug`
|
||||
)
|
||||
expect(gqlMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('handles spaces and extra commas gracefully in label filter input', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'accessibility , backend ,, . , bug'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: [{name: 'accessibility'}, {name: 'backend'}, {name: 'bug'}],
|
||||
'label-operator': 'AND'
|
||||
}
|
||||
}
|
||||
|
||||
const gqlMock = mockGraphQL(
|
||||
{
|
||||
test: /getProject/,
|
||||
return: {
|
||||
organization: {
|
||||
projectNext: {
|
||||
id: 'project-next-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /addProjectNextItem/,
|
||||
return: {
|
||||
addProjectNextItem: {
|
||||
projectNextItem: {
|
||||
id: 'project-next-item-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const infoSpy = jest.spyOn(core, 'info')
|
||||
|
||||
await addToProject()
|
||||
|
||||
expect(gqlMock).toHaveBeenCalled()
|
||||
expect(infoSpy).not.toHaveBeenCalled()
|
||||
expect(outputs.itemId).toEqual('project-next-item-id')
|
||||
})
|
||||
|
||||
test(`throws an error when url isn't a valid project url`, async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/repositories',
|
||||
'github-token': 'gh_token'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: []
|
||||
}
|
||||
}
|
||||
|
||||
const infoSpy = jest.spyOn(core, 'info')
|
||||
const gqlMock = mockGraphQL()
|
||||
await expect(addToProject()).rejects.toThrow(
|
||||
'https://github.com/orgs/github/repositories. Project URL should match the format https://github.com/<orgs-or-users>/<ownerName>/projects/<projectNumber>'
|
||||
)
|
||||
expect(infoSpy).not.toHaveBeenCalled()
|
||||
expect(gqlMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test(`throws an error when url isn't under the github.com domain`, async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://notgithub.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: []
|
||||
}
|
||||
}
|
||||
|
||||
const infoSpy = jest.spyOn(core, 'info')
|
||||
const gqlMock = mockGraphQL()
|
||||
await expect(addToProject()).rejects.toThrow(
|
||||
'https://notgithub.com/orgs/github/projects/1. Project URL should match the format https://github.com/<orgs-or-users>/<ownerName>/projects/<projectNumber>'
|
||||
)
|
||||
expect(infoSpy).not.toHaveBeenCalled()
|
||||
expect(gqlMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('constructs the correct graphQL query given an organization owner', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/orgs/github/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'bug, new'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: [{name: 'bug'}]
|
||||
}
|
||||
}
|
||||
|
||||
const gqlMock = mockGraphQL(
|
||||
{
|
||||
test: /getProject/,
|
||||
return: {
|
||||
organization: {
|
||||
projectNext: {
|
||||
id: 'project-next-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /addProjectNextItem/,
|
||||
return: {
|
||||
addProjectNextItem: {
|
||||
projectNextItem: {
|
||||
id: 'project-next-item-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await addToProject()
|
||||
|
||||
expect(gqlMock).toHaveBeenNthCalledWith(1, expect.stringContaining('organization(login: $ownerName)'), {
|
||||
ownerName: 'github',
|
||||
projectNumber: 1
|
||||
})
|
||||
})
|
||||
|
||||
test('constructs the correct graphQL query given a user owner', async () => {
|
||||
mockGetInput({
|
||||
'project-url': 'https://github.com/users/monalisa/projects/1',
|
||||
'github-token': 'gh_token',
|
||||
labeled: 'bug, new'
|
||||
})
|
||||
|
||||
github.context.payload = {
|
||||
issue: {
|
||||
number: 1,
|
||||
labels: [{name: 'bug'}]
|
||||
}
|
||||
}
|
||||
|
||||
const gqlMock = mockGraphQL(
|
||||
{
|
||||
test: /getProject/,
|
||||
return: {
|
||||
organization: {
|
||||
projectNext: {
|
||||
id: 'project-next-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /addProjectNextItem/,
|
||||
return: {
|
||||
addProjectNextItem: {
|
||||
projectNextItem: {
|
||||
id: 'project-next-item-id'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await addToProject()
|
||||
|
||||
expect(gqlMock).toHaveBeenNthCalledWith(1, expect.stringContaining('user(login: $ownerName)'), {
|
||||
ownerName: 'monalisa',
|
||||
projectNumber: 1
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('mustGetOwnerTypeQuery', () => {
|
||||
test('returns organization for orgs ownerType', async () => {
|
||||
const ownerTypeQuery = mustGetOwnerTypeQuery('orgs')
|
||||
|
||||
expect(ownerTypeQuery).toEqual('organization')
|
||||
})
|
||||
|
||||
test('returns user for users ownerType', async () => {
|
||||
const ownerTypeQuery = mustGetOwnerTypeQuery('users')
|
||||
|
||||
expect(ownerTypeQuery).toEqual('user')
|
||||
})
|
||||
|
||||
test('throws an error when an unsupported ownerType is set', async () => {
|
||||
expect(() => {
|
||||
mustGetOwnerTypeQuery('unknown')
|
||||
}).toThrow(`Unsupported ownerType: unknown. Must be one of 'orgs' or 'users'`)
|
||||
})
|
||||
})
|
||||
|
||||
function mockGetInput(mocks: Record<string, string>): jest.SpyInstance {
|
||||
|
||||
3
dist/index.js
generated
vendored
3
dist/index.js
generated
vendored
@@ -35,7 +35,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.addToProject = void 0;
|
||||
exports.mustGetOwnerTypeQuery = exports.addToProject = void 0;
|
||||
const core = __importStar(__nccwpck_require__(2186));
|
||||
const github = __importStar(__nccwpck_require__(5438));
|
||||
// TODO: Ensure this (and the Octokit client) works for non-github.com URLs, as well.
|
||||
@@ -119,6 +119,7 @@ function mustGetOwnerTypeQuery(ownerType) {
|
||||
}
|
||||
return ownerTypeQuery;
|
||||
}
|
||||
exports.mustGetOwnerTypeQuery = mustGetOwnerTypeQuery;
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
2
dist/index.js.map
generated
vendored
2
dist/index.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -115,7 +115,7 @@ export async function addToProject(): Promise<void> {
|
||||
core.setOutput('itemId', addResp.addProjectNextItem.projectNextItem.id)
|
||||
}
|
||||
|
||||
function mustGetOwnerTypeQuery(ownerType?: string): 'organization' | 'user' {
|
||||
export function mustGetOwnerTypeQuery(ownerType?: string): 'organization' | 'user' {
|
||||
const ownerTypeQuery = ownerType === 'orgs' ? 'organization' : ownerType === 'users' ? 'user' : null
|
||||
|
||||
if (!ownerTypeQuery) {
|
||||
|
||||
Reference in New Issue
Block a user