@rosen-bridge/utils 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/lib/constants.d.ts +0 -1
  3. package/dist/lib/constants.d.ts.map +1 -1
  4. package/dist/lib/constants.js +1 -2
  5. package/dist/lib/downloadRosenAssets.d.ts +6 -3
  6. package/dist/lib/downloadRosenAssets.d.ts.map +1 -1
  7. package/dist/lib/downloadRosenAssets.js +15 -10
  8. package/dist/lib/downloadTssBinary.d.ts +13 -0
  9. package/dist/lib/downloadTssBinary.d.ts.map +1 -0
  10. package/dist/lib/downloadTssBinary.js +45 -0
  11. package/dist/lib/index.d.ts +1 -0
  12. package/dist/lib/index.d.ts.map +1 -1
  13. package/dist/lib/index.js +2 -1
  14. package/dist/lib/types/index.d.ts +1 -0
  15. package/dist/lib/types/index.d.ts.map +1 -1
  16. package/dist/lib/types/index.js +1 -1
  17. package/dist/lib/utils/github.d.ts +318 -6
  18. package/dist/lib/utils/github.d.ts.map +1 -1
  19. package/dist/lib/utils/github.js +53 -9
  20. package/dist/lib/utils/rosen.d.ts +5 -0
  21. package/dist/lib/utils/rosen.d.ts.map +1 -1
  22. package/dist/lib/utils/rosen.js +6 -1
  23. package/dist/tsconfig.build.tsbuildinfo +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -0
  25. package/lib/constants.ts +0 -1
  26. package/lib/downloadRosenAssets.ts +21 -10
  27. package/lib/downloadTssBinary.ts +61 -0
  28. package/lib/index.ts +1 -0
  29. package/lib/types/index.ts +2 -0
  30. package/lib/utils/github.ts +74 -8
  31. package/lib/utils/rosen.ts +7 -0
  32. package/package.json +3 -4
  33. package/tests/data/octokit.data.ts +88 -1
  34. package/tests/downloadRosenAssets.spec.ts +39 -9
  35. package/tests/downloadTssBinary.spec.ts +153 -0
  36. package/tests/mocks/octokit.mock.ts +20 -2
  37. package/tests/utils/github.spec.ts +192 -20
  38. package/tests/utils/rosen.spec.ts +39 -1
@@ -3,19 +3,20 @@ import { Octokit } from 'octokit';
3
3
  import { isValidAssetName } from './rosen';
4
4
 
5
5
  import {
6
- CONTRACT_REPO_NAME,
7
6
  DEFAULT_RELEASES_FETCHING_PAGE_SIZE,
8
7
  ROSEN_BRIDGE_ORGANIZATION,
9
8
  } from '../constants';
10
9
 
11
- import { GithubRelease } from '../types';
10
+ import { GithubRelease, SupportedRepo } from '../types';
12
11
 
13
12
  /**
14
13
  * Fetch a page of releases from Github Api in each iteration until there are no
15
14
  * more releases.
15
+ * @param repoName
16
16
  * @param pageSize
17
17
  */
18
18
  async function* fetchReleasesPage(
19
+ repoName: SupportedRepo,
19
20
  pageSize = DEFAULT_RELEASES_FETCHING_PAGE_SIZE
20
21
  ) {
21
22
  const octokit = new Octokit();
@@ -25,7 +26,7 @@ async function* fetchReleasesPage(
25
26
  while (true) {
26
27
  const releasesPage = await octokit.rest.repos.listReleases({
27
28
  owner: ROSEN_BRIDGE_ORGANIZATION,
28
- repo: CONTRACT_REPO_NAME,
29
+ repo: repoName,
29
30
  per_page: pageSize,
30
31
  page: currentPage,
31
32
  });
@@ -42,12 +43,14 @@ async function* fetchReleasesPage(
42
43
  /**
43
44
  * Find the last release matching the predicate. If all releases are iterated and
44
45
  * no matching release is found, return null.
46
+ * @param repoName
45
47
  * @param predicate
46
48
  */
47
49
  const findLastRelease = async (
50
+ repoName: SupportedRepo,
48
51
  predicate: (release: GithubRelease) => boolean = () => true
49
52
  ) => {
50
- const releasesPageIterator = fetchReleasesPage();
53
+ const releasesPageIterator = fetchReleasesPage(repoName);
51
54
 
52
55
  for await (const releasesPage of releasesPageIterator) {
53
56
  const foundRelease = releasesPage.find(predicate);
@@ -59,6 +62,22 @@ const findLastRelease = async (
59
62
  return null;
60
63
  };
61
64
 
65
+ /**
66
+ * get a GitHub release by its tag
67
+ * @param repoName
68
+ * @param tag
69
+ */
70
+ const getReleaseByTag = async (repoName: SupportedRepo, tag: string) => {
71
+ const octokit = new Octokit();
72
+ const release = await octokit.rest.repos.getReleaseByTag({
73
+ owner: ROSEN_BRIDGE_ORGANIZATION,
74
+ repo: repoName,
75
+ tag,
76
+ });
77
+
78
+ return release.data;
79
+ };
80
+
62
81
  /**
63
82
  * Return a function which checks if a release has at least one asset for a
64
83
  * specific chain type
@@ -77,27 +96,74 @@ const isStableReleaseForChainType =
77
96
  (chainType: string) => (release: GithubRelease) =>
78
97
  !release.prerelease && hasAssetForChainType(chainType)(release);
79
98
 
99
+ /**
100
+ * Return a function which checks if tagPrefix is matched with release tag_name
101
+ * @param tagPrefix
102
+ */
103
+ const hasMatchedTagPrefix = (tagPrefix: string) => (release: GithubRelease) => {
104
+ const regex = new RegExp(`^${tagPrefix}`);
105
+ return regex.test(release.tag_name);
106
+ };
107
+
108
+ /**
109
+ * Return a function which checks if a release is a stable (that is, non-prerelease),
110
+ * and tagPrefix is matched with release tag_name
111
+ * @param tagPrefix
112
+ */
113
+ const isStableReleaseForRegexTagType =
114
+ (tagPrefix: string) => (release: GithubRelease) =>
115
+ !release.prerelease && hasMatchedTagPrefix(tagPrefix)(release);
116
+
80
117
  /**
81
118
  * Find latest release (prerelease or non-prerelease) having some asset matching
82
119
  * a specific chain type
120
+ * @param repoName
83
121
  * @param chainType
84
122
  */
85
- const findLatestRelease = async (chainType: string) =>
86
- findLastRelease(hasAssetForChainType(chainType));
123
+ const findLatestRelease = async (repoName: SupportedRepo, chainType: string) =>
124
+ findLastRelease(repoName, hasAssetForChainType(chainType));
87
125
 
88
126
  /**
89
127
  * Find latest stable (that is, non-prerelease) release having some asset matching
90
128
  * a specific chain type
129
+ * @param repoName
91
130
  * @param chainType
92
131
  */
93
- const findLatestStableRelease = async (chainType: string) =>
94
- findLastRelease(isStableReleaseForChainType(chainType));
132
+ const findLatestStableRelease = async (
133
+ repoName: SupportedRepo,
134
+ chainType: string
135
+ ) => findLastRelease(repoName, isStableReleaseForChainType(chainType));
136
+
137
+ /**
138
+ * Find the latest stable (that is, non-prerelease) release that tagPrefix is matched with release tag_name
139
+ * @param repoName
140
+ * @param tagPrefix
141
+ */
142
+ const findLatestStableReleaseByPrefixTag = async (
143
+ repoName: SupportedRepo,
144
+ tagPrefix: string
145
+ ) => findLastRelease(repoName, isStableReleaseForRegexTagType(tagPrefix));
146
+
147
+ /**
148
+ * Find the latest release that tagPrefix is matched with release tag_name
149
+ * @param repoName
150
+ * @param tagPrefix
151
+ */
152
+ const findLatestReleaseByPrefixTag = async (
153
+ repoName: SupportedRepo,
154
+ tagPrefix: string
155
+ ) => findLastRelease(repoName, hasMatchedTagPrefix(tagPrefix));
95
156
 
96
157
  export {
97
158
  fetchReleasesPage,
98
159
  findLastRelease,
99
160
  findLatestRelease,
100
161
  findLatestStableRelease,
162
+ findLatestStableReleaseByPrefixTag,
163
+ findLatestReleaseByPrefixTag,
164
+ getReleaseByTag,
101
165
  hasAssetForChainType,
102
166
  isStableReleaseForChainType,
167
+ isStableReleaseForRegexTagType,
168
+ hasMatchedTagPrefix,
103
169
  };
@@ -6,6 +6,13 @@
6
6
  export const isValidAssetName = (chainType: string) => (assetName: string) =>
7
7
  new RegExp(`(contracts-.+|tokensMap)-${chainType}-.+.json`).test(assetName);
8
8
 
9
+ /**
10
+ * Check if an OS name is a valid supported tss OS
11
+ * @param OSName
12
+ */
13
+ export const isValidOS = (OSName: string) => (releaseAssetName: string) =>
14
+ new RegExp(`(rosenTss-${OSName}-.+).zip`).test(releaseAssetName);
15
+
9
16
  /**
10
17
  * Remove chain type and tag from the asset name and optionally replaces them
11
18
  * with a suffix
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rosen-bridge/utils",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "description": "Misc utility functions used inside Rosen bridge projects",
5
5
  "main": "dist/lib/index.js",
6
6
  "types": "dist/lib/index.d.ts",
@@ -10,8 +10,8 @@
10
10
  "lint": "eslint --fix . && npm run prettify",
11
11
  "build": "tsc --build tsconfig.build.json",
12
12
  "type-check": "tsc --noEmit",
13
- "test": "jest",
14
- "coverage": "jest --coverage",
13
+ "test": "jest --runInBand",
14
+ "coverage": "jest --coverage --runInBand",
15
15
  "release": "npm run test && npm run build && npm publish --access public"
16
16
  },
17
17
  "repository": {
@@ -22,7 +22,6 @@
22
22
  "devDependencies": {
23
23
  "@types/download": "^8.0.2",
24
24
  "@babel/preset-env": "^7.19.0",
25
- "@types/download": "^8.0.2",
26
25
  "@types/jest": "^29.1.2",
27
26
  "@types/node": "^18.0.0",
28
27
  "@typescript-eslint/eslint-plugin": "^5.30.7",
@@ -4,6 +4,7 @@ export type PartialReleases = Partial<GithubRelease>[];
4
4
 
5
5
  export const mainNetPrereleaseRelease = {
6
6
  id: 1,
7
+ tag_name: '1',
7
8
  prerelease: true,
8
9
  assets: [
9
10
  {
@@ -20,6 +21,7 @@ export const mainNetPrereleaseRelease = {
20
21
 
21
22
  export const mainNetStableRelease = {
22
23
  id: 2,
24
+ tag_name: '2',
23
25
  prerelease: false,
24
26
  assets: [
25
27
  {
@@ -34,8 +36,80 @@ export const mainNetStableRelease = {
34
36
  ],
35
37
  };
36
38
 
39
+ export const tssTag1 = {
40
+ id: 1,
41
+ tag_name: 'tss-api-1.0.0',
42
+ name: 'tss-api-1.0.0',
43
+ prerelease: false,
44
+ assets: [
45
+ {
46
+ name: 'rosenTss-linux-tss-api-1.0.0.zip',
47
+ browser_download_url:
48
+ 'https://example.com/sign-protocols/releases/download/tss-api-1.0.0/rosenTss-linux-tss-api-1.0.0.zip',
49
+ } as any,
50
+ {
51
+ name: 'rosenTss-macOS-tss-api-1.0.0.zip',
52
+ browser_download_url:
53
+ 'https://example.com/sign-protocols/releases/download/tss-api-1.0.0/rosenTss-macOS-tss-api-1.0.0.zip',
54
+ } as any,
55
+ {
56
+ name: 'rosenTss-windows-tss-api-1.0.0.zip',
57
+ browser_download_url:
58
+ 'https://example.com/sign-protocols/releases/download/tss-api-1.0.0/rosenTss-windows-tss-api-1.0.0.zip',
59
+ } as any,
60
+ ],
61
+ };
62
+ export const tssTag2 = {
63
+ id: 2,
64
+ tag_name: 'tss-api-2.0.0',
65
+ name: 'tss-api-2.0.0',
66
+ prerelease: false,
67
+ assets: [
68
+ {
69
+ name: 'rosenTss-linux-tss-api-2.0.0.zip',
70
+ browser_download_url:
71
+ 'https://example.com/sign-protocols/releases/download/tss-api-2.0.0/rosenTss-linux-tss-api-2.0.0.zip',
72
+ } as any,
73
+ {
74
+ name: 'rosenTss-macOS-tss-api-2.0.0.zip',
75
+ browser_download_url:
76
+ 'https://example.com/sign-protocols/releases/download/tss-api-2.0.0/rosenTss-macOS-tss-api-2.0.0.zip',
77
+ } as any,
78
+ {
79
+ name: 'rosenTss-windows-tss-api-2.0.0.zip',
80
+ browser_download_url:
81
+ 'https://example.com/sign-protocols/releases/download/tss-api-2.0.0/rosenTss-windows-tss-api-2.0.0.zip',
82
+ } as any,
83
+ ],
84
+ };
85
+
86
+ export const tssTag3PreRelease = {
87
+ id: 3,
88
+ tag_name: 'tss-api-3.0.0',
89
+ name: 'tss-api-3.0.0',
90
+ prerelease: true,
91
+ assets: [
92
+ {
93
+ name: 'rosenTss-linux-tss-api-3.0.0.zip',
94
+ browser_download_url:
95
+ 'https://example.com/sign-protocols/releases/download/tss-api-3.0.0/rosenTss-linux-tss-api-3.0.0.zip',
96
+ } as any,
97
+ {
98
+ name: 'rosenTss-macOS-tss-api-3.0.0.zip',
99
+ browser_download_url:
100
+ 'https://example.com/sign-protocols/releases/download/tss-api-3.0.0/rosenTss-macOS-tss-api-3.0.0.zip',
101
+ } as any,
102
+ {
103
+ name: 'rosenTss-windows-tss-api-3.0.0.zip',
104
+ browser_download_url:
105
+ 'https://example.com/sign-protocols/releases/download/tss-api-3.0.0/rosenTss-windows-tss-api-3.0.0.zip',
106
+ } as any,
107
+ ],
108
+ };
109
+
37
110
  export const testNetPrereleaseRelease = {
38
111
  id: 4,
112
+ tag_name: '4',
39
113
  prerelease: true,
40
114
  assets: [
41
115
  {
@@ -48,6 +122,7 @@ export const testNetPrereleaseRelease = {
48
122
 
49
123
  export const testNetStableRelease = {
50
124
  id: 5,
125
+ tag_name: '5',
51
126
  prerelease: false,
52
127
  assets: [
53
128
  {
@@ -58,11 +133,12 @@ export const testNetStableRelease = {
58
133
  ],
59
134
  };
60
135
 
61
- export const releases = [
136
+ export const contractReleases = [
62
137
  mainNetPrereleaseRelease,
63
138
  mainNetStableRelease,
64
139
  {
65
140
  id: 3,
141
+ tag_name: '3',
66
142
  prerelease: false,
67
143
  assets: [
68
144
  {
@@ -76,6 +152,7 @@ export const releases = [
76
152
  testNetStableRelease,
77
153
  {
78
154
  id: 6,
155
+ tag_name: '6',
79
156
  prerelease: false,
80
157
  assets: [
81
158
  {
@@ -87,6 +164,7 @@ export const releases = [
87
164
  },
88
165
  {
89
166
  id: 7,
167
+ tag_name: '7',
90
168
  prerelease: false,
91
169
  assets: [
92
170
  {
@@ -98,6 +176,7 @@ export const releases = [
98
176
  },
99
177
  {
100
178
  id: 8,
179
+ tag_name: '8',
101
180
  prerelease: false,
102
181
  assets: [
103
182
  {
@@ -109,6 +188,7 @@ export const releases = [
109
188
  },
110
189
  {
111
190
  id: 9,
191
+ tag_name: '9',
112
192
  prerelease: false,
113
193
  assets: [
114
194
  {
@@ -119,3 +199,10 @@ export const releases = [
119
199
  ],
120
200
  },
121
201
  ] satisfies PartialReleases;
202
+
203
+ export const tssReleases = [
204
+ mainNetStableRelease, // in case of sign-protocols mono repo we have other tags
205
+ tssTag3PreRelease,
206
+ tssTag2,
207
+ tssTag1,
208
+ ] satisfies PartialReleases;
@@ -7,15 +7,16 @@ import { RosenAssetsDownloadError } from '../lib';
7
7
  import {
8
8
  mainNetPrereleaseRelease,
9
9
  mainNetStableRelease,
10
+ contractReleases,
10
11
  } from './data/octokit.data';
11
12
 
12
- import { mockOctokit } from './mocks/octokit.mock';
13
+ import { mockOctokit, mockOctokitGetReleaseByTag } from './mocks/octokit.mock';
13
14
 
14
15
  jest.mock('download');
15
16
 
16
17
  describe('downloadRosenAssets', () => {
17
18
  beforeEach(() => {
18
- mockOctokit();
19
+ mockOctokit(contractReleases);
19
20
  });
20
21
 
21
22
  /**
@@ -23,7 +24,7 @@ describe('downloadRosenAssets', () => {
23
24
  * @dependencies
24
25
  * - mocked Octokit
25
26
  * @scenario
26
- * - mock Octokit `listReleases` to return 9 releases
27
+ * - mock Octokit `listReleases` to return 9 contractReleases
27
28
  * - call `downloadRosenAssets` with mainnet chain type and `rosen` download
28
29
  * directory
29
30
  * @expected
@@ -59,7 +60,7 @@ describe('downloadRosenAssets', () => {
59
60
  * @dependencies
60
61
  * - mocked Octokit
61
62
  * @scenario
62
- * - mock Octokit `listReleases` to return 9 releases
63
+ * - mock Octokit `listReleases` to return 9 contractReleases
63
64
  * - call `downloadRosenAssets` with mainnet chain type, `rosen` download
64
65
  * directory and including prereleases
65
66
  * @expected
@@ -71,7 +72,10 @@ describe('downloadRosenAssets', () => {
71
72
  * corresponding truncated asset name
72
73
  */
73
74
  it('should download Rosen assets correctly when including prereleases', async () => {
74
- await downloadRosenAssets('mainnet', 'rosen', true);
75
+ jest.mocked(download).mockClear();
76
+ await downloadRosenAssets('mainnet', 'rosen', {
77
+ includePrereleases: true,
78
+ });
75
79
 
76
80
  expect(download).toHaveBeenCalledWith(
77
81
  mainNetPrereleaseRelease.assets[0].browser_download_url,
@@ -95,7 +99,7 @@ describe('downloadRosenAssets', () => {
95
99
  * @dependencies
96
100
  * - mocked Octokit
97
101
  * @scenario
98
- * - mock Octokit `listReleases` to return 9 releases
102
+ * - mock Octokit `listReleases` to return 9 contractReleases
99
103
  * - call `downloadRosenAssets` with mainnet chain type, `rosen` download
100
104
  * directory, including prereleases and a providing a suffix
101
105
  * @expected
@@ -107,7 +111,9 @@ describe('downloadRosenAssets', () => {
107
111
  * truncated asset name
108
112
  */
109
113
  it('should download Rosen assets and add a suffix correctly', async () => {
110
- await downloadRosenAssets('mainnet', 'rosen', false, 'suffix');
114
+ await downloadRosenAssets('mainnet', 'rosen', {
115
+ nameSuffix: 'suffix',
116
+ });
111
117
 
112
118
  expect(download).toHaveBeenCalledWith(
113
119
  mainNetStableRelease.assets[0].browser_download_url,
@@ -125,6 +131,30 @@ describe('downloadRosenAssets', () => {
125
131
  );
126
132
  });
127
133
 
134
+ /**
135
+ * @target `downloadRosenAssets` should download a Rosen asset by tag
136
+ * @dependencies
137
+ * - mocked `getReleaseByTag` of Octokit
138
+ * @scenario
139
+ * - call `downloadRosenAssets` with a specific tag
140
+ * @expected
141
+ * - `download` should be called with the assets of "3" tag release
142
+ */
143
+ it('should download a Rosen asset by tag', async () => {
144
+ mockOctokitGetReleaseByTag(contractReleases);
145
+ await downloadRosenAssets('mainnet', 'rosen', {
146
+ tag: '3',
147
+ });
148
+
149
+ expect(download).toHaveBeenCalledWith(
150
+ contractReleases[2].assets[0].browser_download_url,
151
+ 'rosen',
152
+ {
153
+ filename: 'contracts-awesomechain.json',
154
+ }
155
+ );
156
+ });
157
+
128
158
  /**
129
159
  * @target `downloadRosenAssets` should not call `download` function when no
130
160
  * matching release is found
@@ -132,7 +162,7 @@ describe('downloadRosenAssets', () => {
132
162
  * - mocked Octokit
133
163
  * - emptied mocked download package
134
164
  * @scenario
135
- * - mock Octokit `listReleases` to return 9 releases
165
+ * - mock Octokit `listReleases` to return 9 contractReleases
136
166
  * - clear download package mock data (so that we can check calls count)
137
167
  * - call `downloadRosenAssets` with "no-release-net" chain type and `rosen`
138
168
  * download directory
@@ -153,7 +183,7 @@ describe('downloadRosenAssets', () => {
153
183
  * - mocked Octokit
154
184
  * - mocked download package
155
185
  * @scenario
156
- * - mock Octokit `listReleases` to return 9 releases
186
+ * - mock Octokit `listReleases` to return 9 contractReleases
157
187
  * - mock download package to throw an error
158
188
  * - call `downloadRosenAssets` with mainnet chain type and `rosen` download
159
189
  * directory
@@ -0,0 +1,153 @@
1
+ import download from 'download';
2
+
3
+ import { downloadTssBinary } from '../lib';
4
+ import { RosenAssetsDownloadError } from '../lib';
5
+
6
+ import {
7
+ tssReleases,
8
+ tssTag1,
9
+ tssTag2,
10
+ tssTag3PreRelease,
11
+ } from './data/octokit.data';
12
+
13
+ import { mockOctokit, mockOctokitGetReleaseByTag } from './mocks/octokit.mock';
14
+
15
+ jest.mock('download');
16
+
17
+ describe('downloadTssBinary', () => {
18
+ beforeEach(() => {
19
+ mockOctokit(tssReleases);
20
+ });
21
+
22
+ /**
23
+ * @target `downloadTssBinary` should download Tss binary correctly by specific tag
24
+ * @dependencies
25
+ * - mocked Octokit
26
+ * - mocked Octokit GetReleaseByTag
27
+ * @scenario
28
+ * - mock Octokit `listReleases` to return tssReleases
29
+ * - mock Octokit GetReleaseByTag to return desired release
30
+ * - call `downloadTssBinary` with Windows OS name, `tss-api-1.0.0` and `rosen` download
31
+ * directory
32
+ * @expected
33
+ * - `download` function should be called with third asset of tss-api stable
34
+ * release (windows) download url and `bin` download directory
35
+ */
36
+ it('should download Tss binary correctly with specific tag', async () => {
37
+ mockOctokitGetReleaseByTag(tssReleases);
38
+ await downloadTssBinary('bin', {
39
+ osName: 'windows',
40
+ tag: 'tss-api-1.0.0',
41
+ regex: false,
42
+ });
43
+
44
+ expect(download).toHaveBeenCalledWith(
45
+ tssTag1.assets[2].browser_download_url,
46
+ 'bin'
47
+ );
48
+ });
49
+
50
+ /**
51
+ * @target `downloadTssBinary` should download Tss binary correctly by
52
+ * prefix of a tag
53
+ * @dependencies
54
+ * - mocked Octokit
55
+ * @scenario
56
+ * - mock Octokit `listReleases` to return tssReleases
57
+ * - call `downloadTssBinary` with linux OS name, prefix tag `tss-api` and
58
+ * regex should be true
59
+ * @expected
60
+ * - `download` function should be called with first asset of tss-api stable
61
+ * release (linux) download url and `bin` download directory
62
+ */
63
+ it('should download Tss binary correctly with prefix of tag', async () => {
64
+ await downloadTssBinary('bin', {
65
+ osName: 'linux',
66
+ tag: 'tss-api',
67
+ regex: true,
68
+ });
69
+
70
+ expect(download).toHaveBeenCalledWith(
71
+ tssTag2.assets[0].browser_download_url,
72
+ 'bin'
73
+ );
74
+ });
75
+
76
+ /**
77
+ * @target `downloadTssBinary` should download Tss binary correctly by
78
+ * prefix of a tag for an included prereleases release
79
+ * @dependencies
80
+ * - mocked Octokit
81
+ * @scenario
82
+ * - mock Octokit `listReleases` to return tssReleases
83
+ * - call `downloadTssBinary` with linux OS name, prefix tag `tss-api`,
84
+ * enable includePrereleases and regex should be true
85
+ * @expected
86
+ * - `download` function should be called with first asset of tss-api prerelease
87
+ * release (linux) download url and `bin` download directory
88
+ */
89
+ it('should download prerelease Tss binary correctly with prefix of tag', async () => {
90
+ await downloadTssBinary('bin', {
91
+ osName: 'linux',
92
+ tag: 'tss-api',
93
+ regex: true,
94
+ includePrereleases: true,
95
+ });
96
+
97
+ expect(download).toHaveBeenCalledWith(
98
+ tssTag3PreRelease.assets[0].browser_download_url,
99
+ 'bin'
100
+ );
101
+ });
102
+
103
+ /**
104
+ * @target `downloadTssBinary` should not call `download` function when no
105
+ * matching release is found
106
+ * @dependencies
107
+ * - mocked Octokit
108
+ * - emptied mocked download package
109
+ * @scenario
110
+ * - mock Octokit `listReleases` to return tssReleases
111
+ * - clear download package mock data (so that we can check calls count)
112
+ * - call `downloadTssBinary` with "no-release-tag", osName linux and `bin`
113
+ * download directory
114
+ * @expected
115
+ * - `download` function should not get called
116
+ */
117
+ it('should not call `download` function when no matching release is found', async () => {
118
+ jest.mocked(download).mockClear();
119
+
120
+ await downloadTssBinary('bin', {
121
+ osName: 'linux',
122
+ tag: 'no-release-tag',
123
+ regex: true,
124
+ });
125
+
126
+ expect(download).toHaveBeenCalledTimes(0);
127
+ });
128
+
129
+ /**
130
+ * @target `downloadTssBinary` should throw an error when an error happens
131
+ * @dependencies
132
+ * - mocked Octokit
133
+ * - mocked download package
134
+ * @scenario
135
+ * - mock Octokit `listReleases` to return tssReleases
136
+ * - mock download package to throw an error
137
+ * - call `downloadTssBinary` with linux OS name, prefix tag `tss-api` and
138
+ * regex should be true
139
+ * @expected
140
+ * - `download` function should throw `RosenAssetsDownloadError`
141
+ */
142
+ it('should throw an error when an error happens', async () => {
143
+ jest.mocked(download).mockRejectedValue(new Error('Bad!'));
144
+
145
+ const downloadPromise = downloadTssBinary('bin', {
146
+ osName: 'linux',
147
+ tag: 'tss-api',
148
+ regex: true,
149
+ });
150
+
151
+ await expect(downloadPromise).rejects.toThrow(RosenAssetsDownloadError);
152
+ });
153
+ });
@@ -1,10 +1,10 @@
1
1
  import { Octokit } from 'octokit';
2
2
 
3
- import { releases } from '../data/octokit.data';
3
+ import { contractReleases, PartialReleases } from '../data/octokit.data';
4
4
 
5
5
  import { DEFAULT_RELEASES_FETCHING_PAGE_SIZE } from '../../lib/constants';
6
6
 
7
- export const mockOctokit = () =>
7
+ export const mockOctokit = (releases: any[]) =>
8
8
  jest.mocked(Octokit).mockImplementation(() => {
9
9
  let page = 0;
10
10
  return {
@@ -21,3 +21,21 @@ export const mockOctokit = () =>
21
21
  },
22
22
  } as any;
23
23
  });
24
+
25
+ /**
26
+ * mock `getReleaseByTag` of Octokit
27
+ */
28
+ export const mockOctokitGetReleaseByTag = (releases: PartialReleases) =>
29
+ jest.mocked(Octokit).mockImplementation(() => {
30
+ return {
31
+ rest: {
32
+ repos: {
33
+ getReleaseByTag: async ({ tag }: { tag: string }) => {
34
+ return {
35
+ data: releases.find((release) => release.tag_name === tag),
36
+ };
37
+ },
38
+ },
39
+ },
40
+ } as any;
41
+ });