Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit ea1a6a9

Browse files
committed
test(trdl-actions): cover lib/trdl-cli
Signed-off-by: Alexandr Zaytsev <[email protected]>
1 parent f1ff341 commit ea1a6a9

File tree

5 files changed

+173
-4
lines changed

5 files changed

+173
-4
lines changed

lib/optional.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export function optionalToArray<Type>(arg: Type | undefined): Type[] {
33
return arg ? [arg] : []
44
}
55

6+
// optional object property
67
export function optionalToObject<Type>(key: string, value: Type | undefined): Record<string, Type> {
78
return value ? { [key]: value } : {}
89
}

lib/trdl-cli.test.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { beforeEach, describe, it, expect, jest } from '@jest/globals'
2+
import * as io from '../test/mocks/io'
3+
import * as libExec from '../test/mocks/lib-exec'
4+
import type { ListItem, TrdlCli as TrdlCliType } from './trdl-cli'
5+
6+
// Mocks should be declared before the module being tested is imported.
7+
jest.unstable_mockModule('@actions/io', () => io)
8+
jest.unstable_mockModule('./exec', () => libExec)
9+
10+
// The module being tested should be imported dynamically. This ensures that the
11+
// mocks are used in place of any actual dependencies.
12+
const { TrdlCli } = await import('./trdl-cli')
13+
14+
describe('trdl-cli.ts', function () {
15+
let cli: TrdlCliType
16+
let trdlName: string
17+
18+
beforeEach(function () {
19+
cli = new TrdlCli()
20+
trdlName = cli.defaults().repo
21+
})
22+
23+
describe('defaults', function () {
24+
it('should work', function () {
25+
expect(cli.defaults()).toEqual({
26+
repo: trdlName,
27+
group: '0',
28+
channel: 'stable'
29+
})
30+
})
31+
})
32+
33+
describe('mustExist', function () {
34+
it('should not throw error if io.which does not throws an error', async function () {
35+
const result = await cli.mustExist()
36+
expect(result).toBeUndefined()
37+
expect(io.which).toHaveBeenCalledWith(trdlName, true)
38+
})
39+
it('should throw error if io.which throws an error', async function () {
40+
const err0 = new Error('some err')
41+
io.which.mockRejectedValueOnce(err0)
42+
await expect(cli.mustExist()).rejects.toEqual(err0)
43+
expect(io.which).toHaveBeenCalledWith(trdlName, true)
44+
})
45+
})
46+
47+
describe('add', function () {
48+
it('should work', async function () {
49+
const repo = 'some repo'
50+
const url = 'some url'
51+
const rootSha512 = 'some root sha512'
52+
const rootVersion = 'some root version'
53+
const result = await cli.add({ repo, url, rootVersion, rootSha512 })
54+
expect(result).toBeUndefined()
55+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['add', repo, url, rootVersion, rootSha512])
56+
})
57+
})
58+
59+
describe('remove', function () {
60+
it('should work', async function () {
61+
const repo = 'some repo'
62+
const result = await cli.remove({ repo })
63+
expect(result).toBeUndefined()
64+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['remove', repo])
65+
})
66+
})
67+
68+
describe('update', function () {
69+
it('should work with required args and w/o options', async function () {
70+
const repo = 'some repo'
71+
const group = 'some group'
72+
const result = await cli.update({ repo, group })
73+
expect(result).toBeUndefined()
74+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['update', repo, group], { env: process.env })
75+
})
76+
it('should work with all args but w/o options', async function () {
77+
const repo = 'some repo'
78+
const group = 'some group'
79+
const channel = 'some channel'
80+
const result = await cli.update({ repo, group, channel })
81+
expect(result).toBeUndefined()
82+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['update', repo, group, channel], { env: process.env })
83+
})
84+
it('should work with all args and options', async function () {
85+
const repo = 'some repo'
86+
const group = 'some group'
87+
const channel = 'some channel'
88+
const inBackground = false
89+
const result = await cli.update({ repo, group, channel }, { inBackground })
90+
expect(result).toBeUndefined()
91+
const expectedEnv = { ...process.env, TRDL_IN_BACKGROUND: String(inBackground) }
92+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['update', repo, group, channel], { env: expectedEnv })
93+
})
94+
})
95+
96+
describe('binPath', function () {
97+
it('should work with required args', async function () {
98+
const stdout = ['some', 'stdout']
99+
libExec.execOutput.mockResolvedValueOnce({ stdout, stderr: [], exitCode: 0 })
100+
const repo = 'some repo'
101+
const group = 'some group'
102+
const execOpts = {
103+
failOnStdErr: false,
104+
ignoreReturnCode: true
105+
}
106+
const result = await cli.binPath({ repo, group })
107+
expect(result).toEqual(stdout.join(''))
108+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['bin-path', repo, group], execOpts)
109+
})
110+
it('should work with all args', async function () {
111+
const stdout = ['some', 'stdout']
112+
libExec.execOutput.mockResolvedValueOnce({ stdout, stderr: [], exitCode: 0 })
113+
const repo = 'some repo'
114+
const group = 'some group'
115+
const channel = 'some channel'
116+
const execOpts = {
117+
failOnStdErr: false,
118+
ignoreReturnCode: true
119+
}
120+
const result = await cli.binPath({ repo, group, channel })
121+
expect(result).toEqual(stdout.join(''))
122+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['bin-path', repo, group, channel], execOpts)
123+
})
124+
})
125+
126+
describe('list', function () {
127+
it('should work if underlined call return empty array', async function () {
128+
const stdout: string[] = []
129+
libExec.execOutput.mockResolvedValueOnce({ stdout, stderr: [], exitCode: 0 })
130+
const result = await cli.list()
131+
expect(result).toEqual(stdout)
132+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['list'])
133+
})
134+
it('should work if underlined call return array with item which has required fields', async function () {
135+
const stdout: string[] = ['Name URL Default Channel ', 'trdl https://tuf.trdl.dev stable ']
136+
libExec.execOutput.mockResolvedValueOnce({ stdout, stderr: [], exitCode: 0 })
137+
const result = await cli.list()
138+
const item: ListItem = {
139+
name: 'trdl',
140+
url: 'https://tuf.trdl.dev',
141+
default: 'stable'
142+
}
143+
expect(result).toEqual([item])
144+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['list'])
145+
})
146+
it('should work if underlined call return array with item which all fields', async function () {
147+
const stdout: string[] = ['Name URL Default Channel ', 'trdl https://tuf.trdl.dev stable 2 ']
148+
libExec.execOutput.mockResolvedValueOnce({ stdout, stderr: [], exitCode: 0 })
149+
const result = await cli.list()
150+
const item: ListItem = {
151+
name: 'trdl',
152+
url: 'https://tuf.trdl.dev',
153+
default: 'stable',
154+
channel: '2'
155+
}
156+
expect(result).toEqual([item])
157+
expect(libExec.execOutput).toHaveBeenCalledWith(trdlName, ['list'])
158+
})
159+
})
160+
})

lib/trdl-cli.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { which } from '@actions/io'
22
import { execOutput } from './exec'
3-
import { optionalToArray } from './optional'
3+
import { optionalToArray, optionalToObject } from './optional'
44

55
export class TrdlCli {
66
private readonly name: string
@@ -83,16 +83,16 @@ export interface ListItem {
8383
name: string
8484
url: string
8585
default: string
86-
channel: string
86+
channel?: string
8787
}
8888

8989
function parseLineToItem(line: string): ListItem {
90-
const [name, url, default_, channel] = line.split(/ +/)
90+
const [name, url, default_, channel] = line.trim().split(/ +/)
9191
return {
9292
name,
9393
url,
9494
default: default_,
95-
channel
95+
...optionalToObject('channel', channel)
9696
}
9797
}
9898

test/mocks/io.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { jest } from '@jest/globals'
2+
import type * as io from '@actions/io'
3+
4+
export const which = jest.fn<typeof io.which>()

test/mocks/lib-exec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { jest } from '@jest/globals'
2+
import type * as lib from '../../lib/exec'
3+
4+
export const execOutput = jest.fn<typeof lib.execOutput>()

0 commit comments

Comments
 (0)