Files
slash-command-dispatch/__test__/command-helper.unit.test.ts
dependabot[bot]dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Peter Evans
76bfdd3e8c build(deps-dev): bump prettier from 3.5.3 to 3.6.0 (#411)
* build(deps-dev): bump prettier from 3.5.3 to 3.6.0

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>

* Fix format

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Peter Evans <[email protected]>
2025-06-23 14:18:56 +00:00

410 lines
12 KiB
TypeScript

import {
Inputs,
Command,
SlashCommandPayload,
commandDefaults,
getCommandsConfigFromInputs,
getCommandsConfigFromJson,
actorHasPermission,
configIsValid,
tokeniseCommand,
getSlashCommandPayload
} from '../lib/command-helper'
describe('command-helper tests', () => {
test('building config with required inputs only', async () => {
const commands = ['list', 'of', 'slash', 'commands']
const inputs: Inputs = {
token: '',
reactionToken: '',
reactions: true,
commands: commands,
permission: 'write',
issueType: 'both',
allowEdits: false,
repository: 'peter-evans/slash-command-dispatch',
eventTypeSuffix: '-command',
staticArgs: [],
dispatchType: 'repository',
config: '',
configFromFile: ''
}
const config = getCommandsConfigFromInputs(inputs)
expect(config.length).toEqual(4)
for (var i = 0; i < config.length; i++) {
expect(config[i].command).toEqual(commands[i])
expect(config[i].permission).toEqual(commandDefaults.permission)
expect(config[i].issue_type).toEqual(commandDefaults.issue_type)
expect(config[i].allow_edits).toEqual(commandDefaults.allow_edits)
expect(config[i].repository).toEqual(commandDefaults.repository)
expect(config[i].event_type_suffix).toEqual(
commandDefaults.event_type_suffix
)
expect(config[i].static_args).toEqual(commandDefaults.static_args)
expect(config[i].dispatch_type).toEqual(commandDefaults.dispatch_type)
}
})
test('building config with optional inputs', async () => {
const commands = ['list', 'of', 'slash', 'commands']
const inputs: Inputs = {
token: '',
reactionToken: '',
reactions: true,
commands: commands,
permission: 'admin',
issueType: 'pull-request',
allowEdits: true,
repository: 'owner/repo',
eventTypeSuffix: '-cmd',
staticArgs: ['production', 'region=us-east-1'],
dispatchType: 'workflow',
config: '',
configFromFile: ''
}
const config = getCommandsConfigFromInputs(inputs)
expect(config.length).toEqual(4)
for (var i = 0; i < config.length; i++) {
expect(config[i].command).toEqual(commands[i])
expect(config[i].permission).toEqual(inputs.permission)
expect(config[i].issue_type).toEqual(inputs.issueType)
expect(config[i].allow_edits).toEqual(inputs.allowEdits)
expect(config[i].repository).toEqual(inputs.repository)
expect(config[i].event_type_suffix).toEqual(inputs.eventTypeSuffix)
expect(config[i].static_args).toEqual(inputs.staticArgs)
expect(config[i].dispatch_type).toEqual(inputs.dispatchType)
}
})
test('building config with required JSON only', async () => {
const json = `[
{
"command": "do-stuff"
},
{
"command": "test-all-the-things"
}
]`
const commands = ['do-stuff', 'test-all-the-things']
const config = getCommandsConfigFromJson(json)
expect(config.length).toEqual(2)
for (var i = 0; i < config.length; i++) {
expect(config[i].command).toEqual(commands[i])
expect(config[i].permission).toEqual(commandDefaults.permission)
expect(config[i].issue_type).toEqual(commandDefaults.issue_type)
expect(config[i].allow_edits).toEqual(commandDefaults.allow_edits)
expect(config[i].repository).toEqual(commandDefaults.repository)
expect(config[i].event_type_suffix).toEqual(
commandDefaults.event_type_suffix
)
expect(config[i].static_args).toEqual(commandDefaults.static_args)
expect(config[i].dispatch_type).toEqual(commandDefaults.dispatch_type)
}
})
test('building config with optional JSON properties', async () => {
const json = `[
{
"command": "do-stuff",
"permission": "admin",
"issue_type": "pull-request",
"allow_edits": true,
"repository": "owner/repo",
"event_type_suffix": "-cmd"
},
{
"command": "test-all-the-things",
"permission": "read",
"static_args": [
"production",
"region=us-east-1"
],
"dispatch_type": "workflow"
}
]`
const commands = ['do-stuff', 'test-all-the-things']
const config = getCommandsConfigFromJson(json)
expect(config.length).toEqual(2)
expect(config[0].command).toEqual(commands[0])
expect(config[0].permission).toEqual('admin')
expect(config[0].issue_type).toEqual('pull-request')
expect(config[0].allow_edits).toBeTruthy()
expect(config[0].repository).toEqual('owner/repo')
expect(config[0].event_type_suffix).toEqual('-cmd')
expect(config[0].static_args).toEqual([])
expect(config[0].dispatch_type).toEqual('repository')
expect(config[1].command).toEqual(commands[1])
expect(config[1].permission).toEqual('read')
expect(config[1].issue_type).toEqual(commandDefaults.issue_type)
expect(config[1].static_args).toEqual(['production', 'region=us-east-1'])
expect(config[1].dispatch_type).toEqual('workflow')
})
test('valid config', async () => {
const config: Command[] = [
{
command: 'test',
permission: 'write',
issue_type: 'both',
allow_edits: false,
repository: 'peter-evans/slash-command-dispatch',
event_type_suffix: '-command',
static_args: [],
dispatch_type: 'repository'
}
]
expect(configIsValid(config)).toEqual(null)
})
test('invalid permission level in config', async () => {
const config: Command[] = [
{
command: 'test',
permission: 'test-case-invalid-permission',
issue_type: 'both',
allow_edits: false,
repository: 'peter-evans/slash-command-dispatch',
event_type_suffix: '-command',
static_args: [],
dispatch_type: 'repository'
}
]
expect(configIsValid(config)).toEqual(
`'test-case-invalid-permission' is not a valid 'permission'.`
)
})
test('invalid issue type in config', async () => {
const config: Command[] = [
{
command: 'test',
permission: 'write',
issue_type: 'test-case-invalid-issue-type',
allow_edits: false,
repository: 'peter-evans/slash-command-dispatch',
event_type_suffix: '-command',
static_args: [],
dispatch_type: 'repository'
}
]
expect(configIsValid(config)).toEqual(
`'test-case-invalid-issue-type' is not a valid 'issue-type'.`
)
})
test('invalid dispatch type in config', async () => {
const config: Command[] = [
{
command: 'test',
permission: 'write',
issue_type: 'both',
allow_edits: false,
repository: 'peter-evans/slash-command-dispatch',
event_type_suffix: '-command',
static_args: [],
dispatch_type: 'test-case-invalid-dispatch-type'
}
]
expect(configIsValid(config)).toEqual(
`'test-case-invalid-dispatch-type' is not a valid 'dispatch-type'.`
)
})
test('actor does not have permission', async () => {
expect(actorHasPermission('none', 'read')).toBeFalsy()
expect(actorHasPermission('read', 'triage')).toBeFalsy()
expect(actorHasPermission('triage', 'write')).toBeFalsy()
expect(actorHasPermission('write', 'maintain')).toBeFalsy()
expect(actorHasPermission('maintain', 'admin')).toBeFalsy()
})
test('actor has permission', async () => {
expect(actorHasPermission('read', 'none')).toBeTruthy()
expect(actorHasPermission('triage', 'read')).toBeTruthy()
expect(actorHasPermission('write', 'triage')).toBeTruthy()
expect(actorHasPermission('admin', 'write')).toBeTruthy()
expect(actorHasPermission('write', 'write')).toBeTruthy()
})
test('command arguments are correctly tokenised', async () => {
const command = `a b=c "d e" f-g="h i" "j \\"k\\"" l="m \\"n\\" o"`
const commandTokens = [
`a`,
`b=c`,
`"d e"`,
`f-g="h i"`,
`"j \\"k\\""`,
`l="m \\"n\\" o"`
]
expect(tokeniseCommand(command)).toEqual(commandTokens)
})
test('tokenisation of malformed command arguments', async () => {
const command = `test arg named= quoted arg" named-arg="with \\"quoted value`
const commandTokens = [
'test',
'arg',
'named=',
'quoted',
`arg"`,
`named-arg="with`,
'\\"quoted',
'value'
]
expect(tokeniseCommand(command)).toEqual(commandTokens)
})
test('slash command payload with unnamed args', async () => {
const commandTokens = ['test', 'arg1', 'arg2', 'arg3']
const staticArgs = []
const payload: SlashCommandPayload = {
command: 'test',
args: {
all: 'arg1 arg2 arg3',
unnamed: {
all: 'arg1 arg2 arg3',
arg1: 'arg1',
arg2: 'arg2',
arg3: 'arg3'
},
named: {}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
test('slash command payload with named args', async () => {
const commandTokens = [
'test',
'branch_name=main',
'arg1',
'test-id=123',
'arg2'
]
const staticArgs = []
const payload: SlashCommandPayload = {
command: 'test',
args: {
all: 'branch_name=main arg1 test-id=123 arg2',
unnamed: {
all: 'arg1 arg2',
arg1: 'arg1',
arg2: 'arg2'
},
named: {
branch_name: 'main',
'test-id': '123'
}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
test('slash command payload with named args and static args', async () => {
const commandTokens = ['test', 'branch=main', 'arg1', 'dry-run']
const staticArgs = ['production', 'region=us-east-1']
const payload: SlashCommandPayload = {
command: 'test',
args: {
all: 'production region=us-east-1 branch=main arg1 dry-run',
unnamed: {
all: 'production arg1 dry-run',
arg1: 'production',
arg2: 'arg1',
arg3: 'dry-run'
},
named: {
region: 'us-east-1',
branch: 'main'
}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
test('slash command payload with quoted args', async () => {
const commandTokens = [
`test`,
`a`,
`b=c`,
`"d e"`,
`f-g="h i"`,
`"j \\"k\\""`,
`l="m \\"n\\" o"`
]
const staticArgs = [`msg="x y z"`]
const payload: SlashCommandPayload = {
command: `test`,
args: {
all: `msg="x y z" a b=c "d e" f-g="h i" "j \\"k\\"" l="m \\"n\\" o"`,
unnamed: {
all: `a "d e" "j \\"k\\""`,
arg1: `a`,
arg2: `d e`,
arg3: `j \\"k\\"`
},
named: {
msg: `x y z`,
b: `c`,
'f-g': `h i`,
l: `m \\"n\\" o`
}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
test('slash command payload with malformed named args', async () => {
const commandTokens = ['test', 'branch=', 'arg1', 'e.nv=prod', 'arg2']
const staticArgs = []
const payload: SlashCommandPayload = {
command: 'test',
args: {
all: 'branch= arg1 e.nv=prod arg2',
unnamed: {
all: 'branch= arg1 e.nv=prod arg2',
arg1: 'branch=',
arg2: 'arg1',
arg3: 'e.nv=prod',
arg4: 'arg2'
},
named: {}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
test('slash command payload with malformed quoted args', async () => {
const commandTokens = [
'test',
'arg',
'named=',
'quoted',
`arg"`,
`named-arg="with`,
`\\"quoted`,
'value'
]
const staticArgs = []
const payload: SlashCommandPayload = {
command: 'test',
args: {
all: `arg named= quoted arg" named-arg="with \\"quoted value`,
unnamed: {
all: `arg named= quoted arg" \\"quoted value`,
arg1: 'arg',
arg2: 'named=',
arg3: 'quoted',
arg4: `arg"`,
arg5: `\\"quoted`,
arg6: 'value'
},
named: {
'named-arg': `"with`
}
}
}
expect(getSlashCommandPayload(commandTokens, staticArgs)).toEqual(payload)
})
})