@hot-updater/react-native 1.0.0-rc.17 → 1.0.0-rc.21

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 (240) hide show
  1. package/lib/commonjs/checkForUpdate.js +7 -9
  2. package/lib/commonjs/checkForUpdate.js.map +1 -1
  3. package/lib/commonjs/clientPlugin.js +7 -43
  4. package/lib/commonjs/clientPlugin.js.map +1 -1
  5. package/lib/commonjs/httpClient.js +7 -9
  6. package/lib/commonjs/httpClient.js.map +1 -1
  7. package/lib/commonjs/index.js +10 -0
  8. package/lib/commonjs/index.js.map +1 -1
  9. package/lib/commonjs/native.js +4 -4
  10. package/lib/commonjs/native.js.map +1 -1
  11. package/lib/commonjs/pluginHost.js +26 -190
  12. package/lib/commonjs/pluginHost.js.map +1 -1
  13. package/lib/commonjs/releaseCatalogCache.js +7 -59
  14. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  15. package/lib/commonjs/sdkVersion.js +1 -1
  16. package/lib/module/checkForUpdate.js +1 -3
  17. package/lib/module/checkForUpdate.js.map +1 -1
  18. package/lib/module/clientPlugin.js +1 -41
  19. package/lib/module/clientPlugin.js.map +1 -1
  20. package/lib/module/httpClient.js +1 -3
  21. package/lib/module/httpClient.js.map +1 -1
  22. package/lib/module/index.js +2 -0
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/native.js +1 -1
  25. package/lib/module/native.js.map +1 -1
  26. package/lib/module/pluginHost.js +22 -187
  27. package/lib/module/pluginHost.js.map +1 -1
  28. package/lib/module/releaseCatalogCache.js +3 -54
  29. package/lib/module/releaseCatalogCache.js.map +1 -1
  30. package/lib/module/sdkVersion.js +1 -1
  31. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/clientPlugin.d.ts +1 -184
  33. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/httpClient.d.ts +1 -2
  35. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  36. package/lib/typescript/commonjs/index.d.ts +1 -0
  37. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/native.d.ts +1 -1
  39. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  40. package/lib/typescript/commonjs/pluginHost.d.ts +3 -28
  41. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +1 -13
  43. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  45. package/lib/typescript/commonjs/types.d.ts +1 -1
  46. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/wrap.types.d.ts +2 -2
  48. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  49. package/lib/typescript/module/clientPlugin.d.ts +1 -184
  50. package/lib/typescript/module/clientPlugin.d.ts.map +1 -1
  51. package/lib/typescript/module/httpClient.d.ts +1 -2
  52. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  53. package/lib/typescript/module/index.d.ts +1 -0
  54. package/lib/typescript/module/index.d.ts.map +1 -1
  55. package/lib/typescript/module/native.d.ts +1 -1
  56. package/lib/typescript/module/native.d.ts.map +1 -1
  57. package/lib/typescript/module/pluginHost.d.ts +3 -28
  58. package/lib/typescript/module/pluginHost.d.ts.map +1 -1
  59. package/lib/typescript/module/releaseCatalogCache.d.ts +1 -13
  60. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  61. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  62. package/lib/typescript/module/types.d.ts +1 -1
  63. package/lib/typescript/module/types.d.ts.map +1 -1
  64. package/lib/typescript/module/wrap.types.d.ts +2 -2
  65. package/package.json +7 -16
  66. package/src/checkForUpdate.ts +4 -6
  67. package/src/clientPlugin.ts +17 -231
  68. package/src/httpClient.ts +4 -4
  69. package/src/index.ts +7 -0
  70. package/src/native.ts +1 -1
  71. package/src/pluginHost.ts +24 -241
  72. package/src/releaseCatalogCache.ts +7 -136
  73. package/src/sdkVersion.ts +1 -1
  74. package/src/types.ts +1 -1
  75. package/src/wrap.types.ts +2 -2
  76. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  77. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -2236
  78. package/android/src/test/java/com/hotupdater/HotUpdaterExceptionTest.kt +0 -220
  79. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -264
  80. package/android/src/test/java/com/hotupdater/HotUpdaterRecoveryStateTest.kt +0 -97
  81. package/android/src/test/java/com/hotupdater/InstallIdentityServiceTest.kt +0 -71
  82. package/android/src/test/java/com/hotupdater/KeyValueStorageServiceTest.kt +0 -106
  83. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  84. package/android/src/test/java/com/hotupdater/NoBackupContext.kt +0 -11
  85. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -397
  86. package/android/src/test/java/com/hotupdater/PendingCrashRecoveryTest.kt +0 -44
  87. package/android/src/test/java/com/hotupdater/PreviousProcessExitTest.kt +0 -57
  88. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  89. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  90. package/android/src/test/java/com/hotupdater/TarBrArchiveExtractorTest.kt +0 -206
  91. package/lib/commonjs/appReady.spec.js +0 -360
  92. package/lib/commonjs/appReady.spec.js.map +0 -1
  93. package/lib/commonjs/appReady.test-utils.js +0 -25
  94. package/lib/commonjs/appReady.test-utils.js.map +0 -1
  95. package/lib/commonjs/baseURL.js +0 -16
  96. package/lib/commonjs/baseURL.js.map +0 -1
  97. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  98. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  99. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -936
  100. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  101. package/lib/commonjs/entryImportGraph.spec.js +0 -50
  102. package/lib/commonjs/entryImportGraph.spec.js.map +0 -1
  103. package/lib/commonjs/httpClient.spec.js +0 -171
  104. package/lib/commonjs/httpClient.spec.js.map +0 -1
  105. package/lib/commonjs/index.spec.js +0 -395
  106. package/lib/commonjs/index.spec.js.map +0 -1
  107. package/lib/commonjs/iosInterop.spec.js +0 -18
  108. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  109. package/lib/commonjs/native.spec.js +0 -910
  110. package/lib/commonjs/native.spec.js.map +0 -1
  111. package/lib/commonjs/pluginHost.spec.js +0 -292
  112. package/lib/commonjs/pluginHost.spec.js.map +0 -1
  113. package/lib/commonjs/plugins/insights/eventId.js +0 -129
  114. package/lib/commonjs/plugins/insights/eventId.js.map +0 -1
  115. package/lib/commonjs/plugins/insights/eventId.spec.js +0 -47
  116. package/lib/commonjs/plugins/insights/eventId.spec.js.map +0 -1
  117. package/lib/commonjs/plugins/insights/index.js +0 -272
  118. package/lib/commonjs/plugins/insights/index.js.map +0 -1
  119. package/lib/commonjs/plugins/insights/insights.spec.js +0 -640
  120. package/lib/commonjs/plugins/insights/insights.spec.js.map +0 -1
  121. package/lib/commonjs/plugins/insights/sender.js +0 -128
  122. package/lib/commonjs/plugins/insights/sender.js.map +0 -1
  123. package/lib/commonjs/plugins/insights/sender.spec.js +0 -265
  124. package/lib/commonjs/plugins/insights/sender.spec.js.map +0 -1
  125. package/lib/commonjs/plugins/insights/state.js +0 -145
  126. package/lib/commonjs/plugins/insights/state.js.map +0 -1
  127. package/lib/commonjs/releaseCatalogCache.spec.js +0 -213
  128. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  129. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  130. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  131. package/lib/commonjs/store.notification.spec.js +0 -84
  132. package/lib/commonjs/store.notification.spec.js.map +0 -1
  133. package/lib/commonjs/store.spec.js +0 -182
  134. package/lib/commonjs/store.spec.js.map +0 -1
  135. package/lib/commonjs/updateError.spec.js +0 -149
  136. package/lib/commonjs/updateError.spec.js.map +0 -1
  137. package/lib/commonjs/wrap.progress.spec.js +0 -195
  138. package/lib/commonjs/wrap.progress.spec.js.map +0 -1
  139. package/lib/commonjs/wrap.spec.js +0 -232
  140. package/lib/commonjs/wrap.spec.js.map +0 -1
  141. package/lib/module/appReady.spec.js +0 -359
  142. package/lib/module/appReady.spec.js.map +0 -1
  143. package/lib/module/appReady.test-utils.js +0 -19
  144. package/lib/module/appReady.test-utils.js.map +0 -1
  145. package/lib/module/baseURL.js +0 -11
  146. package/lib/module/baseURL.js.map +0 -1
  147. package/lib/module/catalogCacheNative.spec.js +0 -31
  148. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  149. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -935
  150. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  151. package/lib/module/entryImportGraph.spec.js +0 -50
  152. package/lib/module/entryImportGraph.spec.js.map +0 -1
  153. package/lib/module/httpClient.spec.js +0 -171
  154. package/lib/module/httpClient.spec.js.map +0 -1
  155. package/lib/module/index.spec.js +0 -394
  156. package/lib/module/index.spec.js.map +0 -1
  157. package/lib/module/iosInterop.spec.js +0 -18
  158. package/lib/module/iosInterop.spec.js.map +0 -1
  159. package/lib/module/native.spec.js +0 -909
  160. package/lib/module/native.spec.js.map +0 -1
  161. package/lib/module/pluginHost.spec.js +0 -291
  162. package/lib/module/pluginHost.spec.js.map +0 -1
  163. package/lib/module/plugins/insights/eventId.js +0 -122
  164. package/lib/module/plugins/insights/eventId.js.map +0 -1
  165. package/lib/module/plugins/insights/eventId.spec.js +0 -47
  166. package/lib/module/plugins/insights/eventId.spec.js.map +0 -1
  167. package/lib/module/plugins/insights/index.js +0 -268
  168. package/lib/module/plugins/insights/index.js.map +0 -1
  169. package/lib/module/plugins/insights/insights.spec.js +0 -639
  170. package/lib/module/plugins/insights/insights.spec.js.map +0 -1
  171. package/lib/module/plugins/insights/sender.js +0 -123
  172. package/lib/module/plugins/insights/sender.js.map +0 -1
  173. package/lib/module/plugins/insights/sender.spec.js +0 -265
  174. package/lib/module/plugins/insights/sender.spec.js.map +0 -1
  175. package/lib/module/plugins/insights/state.js +0 -139
  176. package/lib/module/plugins/insights/state.js.map +0 -1
  177. package/lib/module/releaseCatalogCache.spec.js +0 -213
  178. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  179. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  180. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  181. package/lib/module/store.notification.spec.js +0 -85
  182. package/lib/module/store.notification.spec.js.map +0 -1
  183. package/lib/module/store.spec.js +0 -181
  184. package/lib/module/store.spec.js.map +0 -1
  185. package/lib/module/updateError.spec.js +0 -149
  186. package/lib/module/updateError.spec.js.map +0 -1
  187. package/lib/module/wrap.progress.spec.js +0 -196
  188. package/lib/module/wrap.progress.spec.js.map +0 -1
  189. package/lib/module/wrap.spec.js +0 -233
  190. package/lib/module/wrap.spec.js.map +0 -1
  191. package/lib/typescript/commonjs/appReady.test-utils.d.ts +0 -9
  192. package/lib/typescript/commonjs/appReady.test-utils.d.ts.map +0 -1
  193. package/lib/typescript/commonjs/baseURL.d.ts +0 -4
  194. package/lib/typescript/commonjs/baseURL.d.ts.map +0 -1
  195. package/lib/typescript/commonjs/plugins/insights/eventId.d.ts +0 -18
  196. package/lib/typescript/commonjs/plugins/insights/eventId.d.ts.map +0 -1
  197. package/lib/typescript/commonjs/plugins/insights/index.d.ts +0 -40
  198. package/lib/typescript/commonjs/plugins/insights/index.d.ts.map +0 -1
  199. package/lib/typescript/commonjs/plugins/insights/sender.d.ts +0 -74
  200. package/lib/typescript/commonjs/plugins/insights/sender.d.ts.map +0 -1
  201. package/lib/typescript/commonjs/plugins/insights/state.d.ts +0 -46
  202. package/lib/typescript/commonjs/plugins/insights/state.d.ts.map +0 -1
  203. package/lib/typescript/module/appReady.test-utils.d.ts +0 -9
  204. package/lib/typescript/module/appReady.test-utils.d.ts.map +0 -1
  205. package/lib/typescript/module/baseURL.d.ts +0 -4
  206. package/lib/typescript/module/baseURL.d.ts.map +0 -1
  207. package/lib/typescript/module/plugins/insights/eventId.d.ts +0 -18
  208. package/lib/typescript/module/plugins/insights/eventId.d.ts.map +0 -1
  209. package/lib/typescript/module/plugins/insights/index.d.ts +0 -40
  210. package/lib/typescript/module/plugins/insights/index.d.ts.map +0 -1
  211. package/lib/typescript/module/plugins/insights/sender.d.ts +0 -74
  212. package/lib/typescript/module/plugins/insights/sender.d.ts.map +0 -1
  213. package/lib/typescript/module/plugins/insights/state.d.ts +0 -46
  214. package/lib/typescript/module/plugins/insights/state.d.ts.map +0 -1
  215. package/plugins/insights/package.json +0 -8
  216. package/src/appReady.spec.ts +0 -393
  217. package/src/appReady.test-utils.ts +0 -31
  218. package/src/baseURL.ts +0 -15
  219. package/src/catalogCacheNative.spec.ts +0 -63
  220. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -966
  221. package/src/entryImportGraph.spec.ts +0 -65
  222. package/src/httpClient.spec.ts +0 -216
  223. package/src/index.spec.ts +0 -434
  224. package/src/iosInterop.spec.ts +0 -30
  225. package/src/native.spec.ts +0 -978
  226. package/src/pluginHost.spec.ts +0 -297
  227. package/src/plugins/insights/eventId.spec.ts +0 -60
  228. package/src/plugins/insights/eventId.ts +0 -171
  229. package/src/plugins/insights/index.ts +0 -367
  230. package/src/plugins/insights/insights.spec.ts +0 -732
  231. package/src/plugins/insights/sender.spec.ts +0 -287
  232. package/src/plugins/insights/sender.ts +0 -221
  233. package/src/plugins/insights/state.ts +0 -184
  234. package/src/releaseCatalogCache.spec.ts +0 -304
  235. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  236. package/src/store.notification.spec.ts +0 -102
  237. package/src/store.spec.ts +0 -215
  238. package/src/updateError.spec.ts +0 -144
  239. package/src/wrap.progress.spec.ts +0 -232
  240. package/src/wrap.spec.ts +0 -262
@@ -1,935 +0,0 @@
1
- "use strict";
2
-
3
- import { createReleaseCatalogScopeKey, encodeChannelKey } from "@hot-updater/core";
4
- import { beforeEach, describe, expect, it, vi } from "vitest";
5
- import { InvalidUpdateResponseError, UpdateHttpError } from "./updateError.js";
6
- const MINIMUM_RELEASE_ID = "00000000-0000-7000-8000-000000000001";
7
- const RELEASE_ID = "00000000-0000-7000-8000-000000000002";
8
- const ACTIVE_RELEASE_ID = "00000000-0000-7000-8000-000000000003";
9
- const CURRENT_BUNDLE_ID = "00000000-0000-7001-8000-000000000001";
10
- const TARGET_BUNDLE_ID = "00000000-0000-7001-8000-000000000002";
11
- const CATALOG_ID = "project-a";
12
- const CHANNEL = "production";
13
- const CATALOG_HASH = `sha256:${"a".repeat(64)}`;
14
- const SCOPE_KEY = createReleaseCatalogScopeKey({
15
- channelKey: encodeChannelKey(CHANNEL),
16
- platform: "ios",
17
- strategy: "APP_VERSION"
18
- });
19
- const mocks = vi.hoisted(() => {
20
- Reflect.set(globalThis, "HotUpdater", {
21
- SDK_VERSION: "test-sdk-version"
22
- });
23
- return {
24
- addListener: vi.fn(() => () => {}),
25
- acceptReleaseCatalog: vi.fn(() => true),
26
- commitReleaseSelection: vi.fn(async () => true),
27
- getActiveUpdateState: vi.fn(() => ({
28
- activeSelection: null,
29
- highestSeenCatalogs: {},
30
- stableSelection: null,
31
- verificationPending: false
32
- })),
33
- getAppVersion: vi.fn(() => "1.2"),
34
- getBundleId: vi.fn(() => CURRENT_BUNDLE_ID),
35
- getChannel: vi.fn(() => CHANNEL),
36
- getCohort: vi.fn(() => "123"),
37
- getCrashHistory: vi.fn(() => []),
38
- getDefaultChannel: vi.fn(() => CHANNEL),
39
- getFingerprintHash: vi.fn(() => null),
40
- getInstallId: vi.fn(() => "install-id"),
41
- getMinBundleId: vi.fn(() => MINIMUM_RELEASE_ID),
42
- isChannelSwitched: vi.fn(() => false),
43
- isReleaseSelectionCurrent: vi.fn(() => true),
44
- resetChannel: vi.fn(),
45
- stageBundle: vi.fn(async () => ({
46
- delivery: "manifest",
47
- patchFallback: false
48
- }))
49
- };
50
- });
51
- vi.mock("react-native", () => ({
52
- Platform: {
53
- OS: "ios"
54
- }
55
- }));
56
- vi.mock("./native", () => mocks);
57
- const createCatalog = (overrides = {}) => ({
58
- catalogId: CATALOG_ID,
59
- catalogHash: CATALOG_HASH,
60
- fallbackPolicy: "BUILTIN_IF_ACTIVE_INELIGIBLE",
61
- generation: 2,
62
- releases: [{
63
- bundleId: TARGET_BUNDLE_ID,
64
- kind: "BUNDLE",
65
- message: "Release two",
66
- releaseId: RELEASE_ID,
67
- rolloutCohortCount: 1000,
68
- shouldForceUpdate: false,
69
- targetCohorts: []
70
- }],
71
- schemaVersion: 1,
72
- scopeKey: SCOPE_KEY,
73
- ...overrides
74
- });
75
- const createClient = (catalog = createCatalog()) => {
76
- const fetchReleaseCatalog = vi.fn(async () => catalog);
77
- const artifact = {
78
- artifactProtocolVersion: 1,
79
- assets: {},
80
- manifestFileHash: "manifest-hash",
81
- manifestUrl: "https://updates.example.com/manifest.json",
82
- archiveUrl: "https://updates.example.com/bundle.tar.br"
83
- };
84
- const resolveArtifact = vi.fn(async () => artifact);
85
- const session = {
86
- fetchReleaseCatalog,
87
- resolveArtifact
88
- };
89
- const client = {
90
- createSession: vi.fn(async () => session)
91
- };
92
- return {
93
- client,
94
- fetchReleaseCatalog,
95
- resolveArtifact
96
- };
97
- };
98
- /** Records what checks report to plugins, in order. */
99
- const recordPluginEvents = async () => {
100
- const {
101
- configurePlugins
102
- } = await import("./pluginHost");
103
- const events = [];
104
- configurePlugins([{
105
- id: "recorder",
106
- setup: () => ({
107
- onUpdateCheck: result => {
108
- events.push(["onUpdateCheck", result]);
109
- },
110
- onBundleDownloaded: info => {
111
- events.push(["onBundleDownloaded", info]);
112
- },
113
- onUpdateError: error => {
114
- events.push(["onUpdateError", error]);
115
- }
116
- })
117
- }], {
118
- baseURL: "https://updates.example.com"
119
- });
120
- return events;
121
- };
122
- describe("checkForUpdate Release catalog protocol", () => {
123
- beforeEach(() => {
124
- vi.resetModules();
125
- vi.clearAllMocks();
126
- vi.stubGlobal("__DEV__", false);
127
- mocks.acceptReleaseCatalog.mockReturnValue(true);
128
- mocks.getActiveUpdateState.mockReturnValue({
129
- activeSelection: null,
130
- highestSeenCatalogs: {},
131
- stableSelection: null,
132
- verificationPending: false
133
- });
134
- mocks.isReleaseSelectionCurrent.mockReturnValue(true);
135
- mocks.commitReleaseSelection.mockResolvedValue(true);
136
- mocks.stageBundle.mockResolvedValue({
137
- delivery: "manifest",
138
- patchFallback: false
139
- });
140
- });
141
- it("reports the check, then the download only after staging", async () => {
142
- const {
143
- checkForUpdate
144
- } = await import("./checkForUpdate");
145
- const events = await recordPluginEvents();
146
- const {
147
- client
148
- } = createClient();
149
- let complete;
150
- mocks.stageBundle.mockImplementationOnce(() => new Promise(resolve => {
151
- complete = resolve;
152
- }));
153
- const update = await checkForUpdate({
154
- client,
155
- updateStrategy: "appVersion"
156
- });
157
- expect(update?.shouldForceUpdate).toBe(false);
158
- expect(events).toEqual([["onUpdateCheck", {
159
- status: "UPDATE_AVAILABLE",
160
- channel: CHANNEL,
161
- fromBundleId: CURRENT_BUNDLE_ID,
162
- fromReleaseId: null,
163
- toBundleId: TARGET_BUNDLE_ID,
164
- toReleaseId: RELEASE_ID,
165
- transitionKind: "INSTALL",
166
- updateStatus: "UPDATE",
167
- shouldForceUpdate: false,
168
- updateStrategy: "appVersion"
169
- }]]);
170
- const pending = update.updateBundle();
171
- await vi.waitFor(() => expect(mocks.stageBundle).toHaveBeenCalledOnce());
172
- expect(events).toHaveLength(1);
173
- complete({
174
- delivery: "patch",
175
- patchFallback: true
176
- });
177
- await expect(pending).resolves.toBe(true);
178
- expect(events[1]).toEqual(["onBundleDownloaded", {
179
- channel: CHANNEL,
180
- fromBundleId: CURRENT_BUNDLE_ID,
181
- fromReleaseId: null,
182
- toBundleId: TARGET_BUNDLE_ID,
183
- toReleaseId: RELEASE_ID,
184
- updateStrategy: "appVersion",
185
- delivery: "patch",
186
- patchFallback: true
187
- }]);
188
- });
189
- it.each(["nothing new", "failure"])("does not report a download when staging brings %s", async result => {
190
- const {
191
- checkForUpdate
192
- } = await import("./checkForUpdate");
193
- const events = await recordPluginEvents();
194
- const {
195
- client
196
- } = createClient();
197
- if (result === "nothing new") mocks.stageBundle.mockResolvedValueOnce(null);else mocks.stageBundle.mockRejectedValueOnce(new Error("download failed"));
198
- const update = await checkForUpdate({
199
- client,
200
- updateStrategy: "appVersion"
201
- });
202
- await update.updateBundle().catch(() => false);
203
- expect(events.map(([name]) => name)).not.toContain("onBundleDownloaded");
204
- });
205
- it("selects locally and defers Bundle artifact resolution until install", async () => {
206
- const {
207
- checkForUpdate
208
- } = await import("./checkForUpdate");
209
- const {
210
- client,
211
- fetchReleaseCatalog,
212
- resolveArtifact
213
- } = createClient();
214
- const result = await checkForUpdate({
215
- client,
216
- updateStrategy: "appVersion"
217
- });
218
- expect(result).toMatchObject({
219
- id: RELEASE_ID,
220
- releaseId: RELEASE_ID,
221
- transitionKind: "INSTALL"
222
- });
223
- expect(fetchReleaseCatalog).toHaveBeenCalledWith({
224
- appVersion: "1.2.0",
225
- channel: CHANNEL,
226
- fingerprintHash: null,
227
- platform: "ios",
228
- requestHeaders: undefined,
229
- requestTimeout: undefined,
230
- updateStrategy: "appVersion"
231
- });
232
- expect(resolveArtifact).not.toHaveBeenCalled();
233
- await expect(result?.updateBundle()).resolves.toBe(true);
234
- expect(resolveArtifact).toHaveBeenCalledWith({
235
- currentBundleId: CURRENT_BUNDLE_ID,
236
- requestHeaders: undefined,
237
- requestTimeout: undefined,
238
- targetBundleId: TARGET_BUNDLE_ID
239
- });
240
- expect(mocks.stageBundle).toHaveBeenCalledWith(expect.objectContaining({
241
- bundleId: TARGET_BUNDLE_ID,
242
- archiveUrl: "https://updates.example.com/bundle.tar.br",
243
- selection: expect.objectContaining({
244
- catalogId: CATALOG_ID,
245
- releaseId: RELEASE_ID,
246
- scopeKey: SCOPE_KEY
247
- })
248
- }));
249
- });
250
- it("adopts a newer Release for the same Bundle without resolving bytes", async () => {
251
- const active = {
252
- catalogId: CATALOG_ID,
253
- bundleId: TARGET_BUNDLE_ID,
254
- catalogHash: `sha256:${"b".repeat(64)}`,
255
- channel: CHANNEL,
256
- generation: 1,
257
- kind: "BUNDLE",
258
- releaseId: MINIMUM_RELEASE_ID,
259
- scopeKey: SCOPE_KEY,
260
- selectionContextHash: "old-context"
261
- };
262
- mocks.getBundleId.mockReturnValueOnce(TARGET_BUNDLE_ID);
263
- mocks.getActiveUpdateState.mockReturnValueOnce({
264
- activeSelection: active,
265
- highestSeenCatalogs: {},
266
- stableSelection: active,
267
- verificationPending: false
268
- });
269
- const {
270
- checkForUpdate
271
- } = await import("./checkForUpdate");
272
- const forceCatalog = createCatalog({
273
- releases: [{
274
- ...createCatalog().releases[0],
275
- shouldForceUpdate: true
276
- }]
277
- });
278
- const events = await recordPluginEvents();
279
- const {
280
- client,
281
- resolveArtifact
282
- } = createClient(forceCatalog);
283
- const result = await checkForUpdate({
284
- client,
285
- updateStrategy: "appVersion"
286
- });
287
- expect(result).toMatchObject({
288
- id: RELEASE_ID,
289
- shouldForceUpdate: false,
290
- transitionKind: "ADOPT_RELEASE"
291
- });
292
- await expect(result?.updateBundle()).resolves.toBe(true);
293
- expect(resolveArtifact).not.toHaveBeenCalled();
294
- expect(mocks.stageBundle).not.toHaveBeenCalled();
295
- expect(events.map(([name]) => name)).not.toContain("onBundleDownloaded");
296
- expect(mocks.commitReleaseSelection).toHaveBeenCalledWith({
297
- guard: expect.objectContaining({
298
- generation: 2,
299
- scopeKey: SCOPE_KEY
300
- }),
301
- selection: expect.objectContaining({
302
- bundleId: TARGET_BUNDLE_ID,
303
- releaseId: RELEASE_ID
304
- })
305
- });
306
- });
307
- it("reports a same-file adoption as UNCHANGED with the adopted Release", async () => {
308
- const active = {
309
- catalogId: CATALOG_ID,
310
- bundleId: TARGET_BUNDLE_ID,
311
- catalogHash: `sha256:${"b".repeat(64)}`,
312
- channel: CHANNEL,
313
- generation: 1,
314
- kind: "BUNDLE",
315
- releaseId: MINIMUM_RELEASE_ID,
316
- scopeKey: SCOPE_KEY,
317
- selectionContextHash: "old-context"
318
- };
319
- mocks.getBundleId.mockReturnValueOnce(TARGET_BUNDLE_ID);
320
- mocks.getActiveUpdateState.mockReturnValueOnce({
321
- activeSelection: active,
322
- highestSeenCatalogs: {},
323
- stableSelection: active,
324
- verificationPending: false
325
- });
326
- const {
327
- checkForUpdate
328
- } = await import("./checkForUpdate");
329
- const events = await recordPluginEvents();
330
- const {
331
- client
332
- } = createClient();
333
- const result = await checkForUpdate({
334
- client,
335
- updateStrategy: "appVersion"
336
- });
337
- await result?.updateBundle();
338
- expect(events.at(-1)).toEqual(["onUpdateCheck", {
339
- status: "UNCHANGED",
340
- channel: CHANNEL,
341
- bundleId: TARGET_BUNDLE_ID,
342
- releaseId: RELEASE_ID,
343
- previousReleaseId: MINIMUM_RELEASE_ID
344
- }]);
345
- });
346
- it("selects a lower-id Release when explicitly switching scopes", async () => {
347
- const betaChannel = "beta";
348
- const betaScopeKey = createReleaseCatalogScopeKey({
349
- channelKey: encodeChannelKey(betaChannel),
350
- platform: "ios",
351
- strategy: "APP_VERSION"
352
- });
353
- const active = {
354
- catalogId: CATALOG_ID,
355
- bundleId: CURRENT_BUNDLE_ID,
356
- catalogHash: `sha256:${"b".repeat(64)}`,
357
- channel: CHANNEL,
358
- generation: 1,
359
- kind: "BUNDLE",
360
- releaseId: ACTIVE_RELEASE_ID,
361
- scopeKey: SCOPE_KEY,
362
- selectionContextHash: "old-context"
363
- };
364
- mocks.getActiveUpdateState.mockReturnValueOnce({
365
- activeSelection: active,
366
- highestSeenCatalogs: {},
367
- stableSelection: active,
368
- verificationPending: false
369
- });
370
- const betaCatalog = createCatalog({
371
- scopeKey: betaScopeKey
372
- });
373
- const {
374
- checkForUpdate
375
- } = await import("./checkForUpdate");
376
- const {
377
- client
378
- } = createClient(betaCatalog);
379
- const result = await checkForUpdate({
380
- channel: betaChannel,
381
- client,
382
- updateStrategy: "appVersion"
383
- });
384
- expect(result).toMatchObject({
385
- id: RELEASE_ID,
386
- releaseId: RELEASE_ID,
387
- status: "UPDATE",
388
- transitionKind: "INSTALL"
389
- });
390
- });
391
- it("refreshes the same Release receipt when catalog provenance changes", async () => {
392
- const active = {
393
- catalogId: CATALOG_ID,
394
- bundleId: TARGET_BUNDLE_ID,
395
- catalogHash: `sha256:${"b".repeat(64)}`,
396
- channel: CHANNEL,
397
- generation: 1,
398
- kind: "BUNDLE",
399
- releaseId: RELEASE_ID,
400
- scopeKey: SCOPE_KEY,
401
- selectionContextHash: "old-context"
402
- };
403
- mocks.getBundleId.mockReturnValueOnce(TARGET_BUNDLE_ID);
404
- mocks.getActiveUpdateState.mockReturnValueOnce({
405
- activeSelection: active,
406
- highestSeenCatalogs: {},
407
- stableSelection: active,
408
- verificationPending: false
409
- });
410
- const {
411
- checkForUpdate
412
- } = await import("./checkForUpdate");
413
- const {
414
- client,
415
- resolveArtifact
416
- } = createClient();
417
- const result = await checkForUpdate({
418
- client,
419
- updateStrategy: "appVersion"
420
- });
421
- expect(result).toMatchObject({
422
- id: RELEASE_ID,
423
- releaseId: RELEASE_ID,
424
- transitionKind: "ADOPT_RELEASE"
425
- });
426
- await expect(result?.updateBundle()).resolves.toBe(true);
427
- expect(resolveArtifact).not.toHaveBeenCalled();
428
- expect(mocks.stageBundle).not.toHaveBeenCalled();
429
- expect(mocks.commitReleaseSelection).toHaveBeenCalledWith({
430
- guard: expect.objectContaining({
431
- catalogHash: CATALOG_HASH,
432
- generation: 2,
433
- scopeKey: SCOPE_KEY
434
- }),
435
- selection: expect.objectContaining({
436
- bundleId: TARGET_BUNDLE_ID,
437
- catalogHash: CATALOG_HASH,
438
- generation: 2,
439
- releaseId: RELEASE_ID
440
- })
441
- });
442
- });
443
- it("rejects a slow artifact completion after a newer catalog wins", async () => {
444
- mocks.isReleaseSelectionCurrent.mockReturnValueOnce(true).mockReturnValueOnce(false);
445
- const {
446
- StaleReleaseCatalogError
447
- } = await import("./error");
448
- const {
449
- checkForUpdate
450
- } = await import("./checkForUpdate");
451
- const {
452
- client
453
- } = createClient();
454
- const result = await checkForUpdate({
455
- client,
456
- updateStrategy: "appVersion"
457
- });
458
- await expect(result?.updateBundle()).rejects.toBeInstanceOf(StaleReleaseCatalogError);
459
- expect(mocks.stageBundle).not.toHaveBeenCalled();
460
- });
461
- it("installs an older enabled Release as a forced rollback", async () => {
462
- const active = {
463
- catalogId: CATALOG_ID,
464
- bundleId: CURRENT_BUNDLE_ID,
465
- catalogHash: `sha256:${"b".repeat(64)}`,
466
- channel: CHANNEL,
467
- generation: 1,
468
- kind: "BUNDLE",
469
- releaseId: ACTIVE_RELEASE_ID,
470
- scopeKey: SCOPE_KEY,
471
- selectionContextHash: "old-context"
472
- };
473
- mocks.getActiveUpdateState.mockReturnValueOnce({
474
- activeSelection: active,
475
- highestSeenCatalogs: {},
476
- stableSelection: active,
477
- verificationPending: false
478
- });
479
- const catalog = createCatalog({
480
- rollbackReleases: [{
481
- bundleId: TARGET_BUNDLE_ID,
482
- kind: "BUNDLE",
483
- message: "Previous Release",
484
- releaseId: RELEASE_ID,
485
- rolloutCohortCount: 0,
486
- shouldForceUpdate: false,
487
- targetCohorts: []
488
- }]
489
- });
490
- const {
491
- checkForUpdate
492
- } = await import("./checkForUpdate");
493
- const {
494
- client
495
- } = createClient(catalog);
496
- const result = await checkForUpdate({
497
- client,
498
- updateStrategy: "appVersion"
499
- });
500
- expect(result).toMatchObject({
501
- id: RELEASE_ID,
502
- releaseId: RELEASE_ID,
503
- shouldForceUpdate: true,
504
- status: "ROLLBACK",
505
- transitionKind: "INSTALL"
506
- });
507
- await expect(result?.updateBundle()).resolves.toBe(true);
508
- expect(mocks.stageBundle).toHaveBeenCalledWith(expect.objectContaining({
509
- bundleId: TARGET_BUNDLE_ID,
510
- status: "ROLLBACK"
511
- }));
512
- });
513
- it("uses current Bundle identity when migrating an unauthenticated receipt", async () => {
514
- const migratedCurrentBundleId = "00000000-0000-7001-8000-000000000003";
515
- const active = {
516
- catalogId: null,
517
- bundleId: migratedCurrentBundleId,
518
- catalogHash: null,
519
- channel: CHANNEL,
520
- generation: null,
521
- kind: "BUNDLE",
522
- releaseId: null,
523
- scopeKey: null,
524
- selectionContextHash: null
525
- };
526
- mocks.getBundleId.mockReturnValueOnce(migratedCurrentBundleId);
527
- mocks.getActiveUpdateState.mockReturnValueOnce({
528
- activeSelection: active,
529
- highestSeenCatalogs: {},
530
- stableSelection: active,
531
- verificationPending: false
532
- });
533
- const catalog = createCatalog({
534
- releases: [],
535
- rollbackReleases: [{
536
- ...createCatalog().releases[0],
537
- rolloutCohortCount: 0
538
- }]
539
- });
540
- const {
541
- checkForUpdate
542
- } = await import("./checkForUpdate");
543
- const {
544
- client
545
- } = createClient(catalog);
546
- const result = await checkForUpdate({
547
- client,
548
- updateStrategy: "appVersion"
549
- });
550
- expect(result).toMatchObject({
551
- id: RELEASE_ID,
552
- shouldForceUpdate: true,
553
- status: "ROLLBACK",
554
- transitionKind: "INSTALL"
555
- });
556
- });
557
- it.each(["EMBEDDED", "BUILTIN"])("returns a forced %s rollback with its console ID or built-in fallback", async kind => {
558
- const active = {
559
- catalogId: CATALOG_ID,
560
- bundleId: CURRENT_BUNDLE_ID,
561
- catalogHash: `sha256:${"b".repeat(64)}`,
562
- channel: CHANNEL,
563
- generation: 1,
564
- kind: "BUNDLE",
565
- releaseId: MINIMUM_RELEASE_ID,
566
- scopeKey: SCOPE_KEY,
567
- selectionContextHash: "old-context"
568
- };
569
- mocks.getActiveUpdateState.mockReturnValueOnce({
570
- activeSelection: active,
571
- highestSeenCatalogs: {},
572
- stableSelection: active,
573
- verificationPending: false
574
- });
575
- const {
576
- checkForUpdate
577
- } = await import("./checkForUpdate");
578
- const {
579
- client,
580
- resolveArtifact
581
- } = createClient(createCatalog({
582
- releases: kind === "EMBEDDED" ? [{
583
- ...createCatalog().releases[0],
584
- kind,
585
- bundleId: null
586
- }] : [],
587
- rollbackReleases: []
588
- }));
589
- const result = await checkForUpdate({
590
- client,
591
- updateStrategy: "appVersion"
592
- });
593
- expect(result).toMatchObject({
594
- id: kind === "EMBEDDED" ? RELEASE_ID : MINIMUM_RELEASE_ID,
595
- releaseId: kind === "EMBEDDED" ? RELEASE_ID : null,
596
- shouldForceUpdate: true,
597
- status: "ROLLBACK",
598
- transitionKind: kind === "EMBEDDED" ? "USE_EMBEDDED" : "USE_BUILTIN"
599
- });
600
- await expect(result?.updateBundle()).resolves.toBe(true);
601
- expect(mocks.commitReleaseSelection).toHaveBeenCalledWith(expect.objectContaining({
602
- selection: expect.objectContaining({
603
- bundleId: MINIMUM_RELEASE_ID,
604
- kind,
605
- releaseId: kind === "EMBEDDED" ? RELEASE_ID : null
606
- })
607
- }));
608
- expect(resolveArtifact).not.toHaveBeenCalled();
609
- expect(mocks.stageBundle).not.toHaveBeenCalled();
610
- });
611
- it("does not surface a rollback when the app already uses built-in bytes", async () => {
612
- mocks.getBundleId.mockReturnValueOnce(MINIMUM_RELEASE_ID);
613
- const {
614
- checkForUpdate
615
- } = await import("./checkForUpdate");
616
- const {
617
- client
618
- } = createClient(createCatalog({
619
- releases: [],
620
- rollbackReleases: []
621
- }));
622
- await expect(checkForUpdate({
623
- client,
624
- updateStrategy: "appVersion"
625
- })).resolves.toBeNull();
626
- expect(mocks.commitReleaseSelection).not.toHaveBeenCalled();
627
- });
628
- it("reports a rejected generation without selecting or resolving artifacts", async () => {
629
- mocks.acceptReleaseCatalog.mockReturnValueOnce(false);
630
- const onError = vi.fn();
631
- const {
632
- checkForUpdate
633
- } = await import("./checkForUpdate");
634
- const {
635
- client,
636
- resolveArtifact
637
- } = createClient();
638
- await expect(checkForUpdate({
639
- client,
640
- onError,
641
- updateStrategy: "appVersion"
642
- })).resolves.toBeNull();
643
- expect(onError).toHaveBeenCalledWith(expect.objectContaining({
644
- message: "Rejected a stale or inconsistent Release catalog"
645
- }));
646
- expect(resolveArtifact).not.toHaveBeenCalled();
647
- });
648
- it("rejects mismatched catalog scope before native catalog state mutates", async () => {
649
- const wrongScope = createReleaseCatalogScopeKey({
650
- channelKey: encodeChannelKey("beta"),
651
- platform: "ios",
652
- strategy: "APP_VERSION"
653
- });
654
- const onError = vi.fn();
655
- const {
656
- checkForUpdate
657
- } = await import("./checkForUpdate");
658
- const {
659
- client
660
- } = createClient(createCatalog({
661
- scopeKey: wrongScope
662
- }));
663
- await expect(checkForUpdate({
664
- client,
665
- onError,
666
- updateStrategy: "appVersion"
667
- })).resolves.toBeNull();
668
- expect(onError).toHaveBeenCalledWith(expect.objectContaining({
669
- message: "Received an invalid Release catalog"
670
- }));
671
- expect(mocks.acceptReleaseCatalog).not.toHaveBeenCalled();
672
- expect(mocks.commitReleaseSelection).not.toHaveBeenCalled();
673
- expect(mocks.stageBundle).not.toHaveBeenCalled();
674
- });
675
- it("rejects an unexpected Catalog identity before accepting catalog state", async () => {
676
- const active = {
677
- catalogId: "existing-project",
678
- bundleId: CURRENT_BUNDLE_ID,
679
- catalogHash: `sha256:${"b".repeat(64)}`,
680
- channel: CHANNEL,
681
- generation: 1,
682
- kind: "BUNDLE",
683
- releaseId: ACTIVE_RELEASE_ID,
684
- scopeKey: createReleaseCatalogScopeKey({
685
- channelKey: encodeChannelKey(CHANNEL),
686
- platform: "ios",
687
- strategy: "APP_VERSION"
688
- }),
689
- selectionContextHash: "old-context"
690
- };
691
- mocks.getActiveUpdateState.mockReturnValueOnce({
692
- activeSelection: active,
693
- highestSeenCatalogs: {},
694
- stableSelection: active,
695
- verificationPending: false
696
- });
697
- const onError = vi.fn();
698
- const {
699
- checkForUpdate
700
- } = await import("./checkForUpdate");
701
- const {
702
- client
703
- } = createClient();
704
- await expect(checkForUpdate({
705
- client,
706
- onError,
707
- updateStrategy: "appVersion"
708
- })).resolves.toBeNull();
709
- expect(onError).toHaveBeenCalledWith(expect.objectContaining({
710
- message: "Release transition rejected: UNSOLICITED_SCOPE"
711
- }));
712
- expect(mocks.acceptReleaseCatalog).not.toHaveBeenCalled();
713
- });
714
- it("reports a check that found nothing to install as UNCHANGED", async () => {
715
- mocks.getBundleId.mockReturnValueOnce(MINIMUM_RELEASE_ID);
716
- const {
717
- checkForUpdate
718
- } = await import("./checkForUpdate");
719
- const events = await recordPluginEvents();
720
- const {
721
- client
722
- } = createClient(createCatalog({
723
- releases: [],
724
- rollbackReleases: []
725
- }));
726
- await expect(checkForUpdate({
727
- client,
728
- updateStrategy: "appVersion"
729
- })).resolves.toBeNull();
730
- expect(events).toEqual([["onUpdateCheck", {
731
- status: "UNCHANGED",
732
- channel: CHANNEL,
733
- bundleId: MINIMUM_RELEASE_ID,
734
- releaseId: null,
735
- previousReleaseId: null
736
- }]]);
737
- });
738
- it("treats a scope without a catalog as no update, not a failure", async () => {
739
- const onError = vi.fn();
740
- const {
741
- checkForUpdate
742
- } = await import("./checkForUpdate");
743
- const events = await recordPluginEvents();
744
- const {
745
- client,
746
- fetchReleaseCatalog
747
- } = createClient();
748
- fetchReleaseCatalog.mockResolvedValueOnce(null);
749
- await expect(checkForUpdate({
750
- client,
751
- onError,
752
- updateStrategy: "appVersion"
753
- })).resolves.toBeNull();
754
- expect(onError).not.toHaveBeenCalled();
755
- expect(mocks.acceptReleaseCatalog).not.toHaveBeenCalled();
756
- expect(events).toEqual([["onUpdateCheck", expect.objectContaining({
757
- status: "UNCHANGED",
758
- channel: CHANNEL
759
- })]]);
760
- });
761
- it.each([{
762
- label: "an HTTP status",
763
- error: () => new UpdateHttpError(503, "Service Unavailable"),
764
- expected: {
765
- reason: "http",
766
- httpStatus: 503
767
- }
768
- }, {
769
- label: "no response",
770
- error: () => new TypeError("Network request failed"),
771
- expected: {
772
- reason: "network"
773
- }
774
- }, {
775
- label: "a 404 without the no-catalog mark",
776
- error: () => new UpdateHttpError(404, "Not Found"),
777
- expected: {
778
- reason: "http",
779
- httpStatus: 404
780
- }
781
- }, {
782
- label: "a timeout",
783
- error: () => new Error("Request timed out"),
784
- expected: {
785
- reason: "network",
786
- transport: "timeout"
787
- }
788
- }, {
789
- label: "an invalid catalog",
790
- error: () => new InvalidUpdateResponseError("Received an invalid Release catalog"),
791
- expected: {
792
- reason: "invalid_response"
793
- }
794
- }])("reports a check failed by $label", async ({
795
- error,
796
- expected
797
- }) => {
798
- const {
799
- checkForUpdate
800
- } = await import("./checkForUpdate");
801
- const events = await recordPluginEvents();
802
- const {
803
- client,
804
- fetchReleaseCatalog
805
- } = createClient();
806
- const cause = error();
807
- fetchReleaseCatalog.mockRejectedValueOnce(cause);
808
- await expect(checkForUpdate({
809
- client,
810
- updateStrategy: "appVersion"
811
- })).resolves.toBeNull();
812
- expect(events).toEqual([["onUpdateError", {
813
- stage: "check",
814
- resource: "catalog",
815
- ...expected,
816
- channel: CHANNEL,
817
- bundleId: CURRENT_BUNDLE_ID,
818
- releaseId: null,
819
- updateStrategy: "appVersion",
820
- cause
821
- }]]);
822
- });
823
- it.each([{
824
- label: "an artifact request answered 500",
825
- fail: resolveArtifact => resolveArtifact.mockRejectedValueOnce(new UpdateHttpError(500, "Internal Server Error")),
826
- expected: {
827
- stage: "download",
828
- reason: "http",
829
- resource: "artifact",
830
- httpStatus: 500
831
- }
832
- }, {
833
- label: "native extraction",
834
- fail: () => mocks.stageBundle.mockRejectedValueOnce(Object.assign(new Error("Failed to extract archive"), {
835
- code: "UNKNOWN_ERROR",
836
- userInfo: {
837
- reason: "extract",
838
- stage: "install"
839
- }
840
- })),
841
- expected: {
842
- stage: "install",
843
- reason: "extract"
844
- }
845
- }, {
846
- label: "a native HTTP status",
847
- fail: () => mocks.stageBundle.mockRejectedValueOnce(Object.assign(new Error("Failed to download bundle"), {
848
- code: "DOWNLOAD_FAILED",
849
- userInfo: {
850
- httpStatus: 403,
851
- originCode: "ExpiredToken",
852
- reason: "http",
853
- resource: "archive",
854
- stage: "download"
855
- }
856
- })),
857
- expected: {
858
- stage: "download",
859
- reason: "http",
860
- resource: "archive",
861
- httpStatus: 403,
862
- originCode: "ExpiredToken"
863
- }
864
- }, {
865
- label: "a native connection loss",
866
- fail: () => mocks.stageBundle.mockRejectedValueOnce(Object.assign(new Error("The network connection was lost."), {
867
- code: "DOWNLOAD_FAILED",
868
- userInfo: {
869
- reason: "network",
870
- resource: "file",
871
- stage: "download",
872
- transport: "connection"
873
- }
874
- })),
875
- expected: {
876
- stage: "download",
877
- reason: "network",
878
- resource: "file",
879
- transport: "connection"
880
- }
881
- }])("reports an install failed by $label and rethrows it", async ({
882
- fail,
883
- expected
884
- }) => {
885
- const {
886
- checkForUpdate
887
- } = await import("./checkForUpdate");
888
- const events = await recordPluginEvents();
889
- const {
890
- client,
891
- resolveArtifact
892
- } = createClient();
893
- fail(resolveArtifact);
894
- const result = await checkForUpdate({
895
- client,
896
- updateStrategy: "appVersion"
897
- });
898
- await expect(result.updateBundle()).rejects.toThrow();
899
- expect(events.filter(([name]) => name === "onUpdateError")).toEqual([["onUpdateError", expect.objectContaining({
900
- ...expected,
901
- channel: CHANNEL,
902
- bundleId: CURRENT_BUNDLE_ID,
903
- targetBundleId: TARGET_BUNDLE_ID,
904
- targetReleaseId: RELEASE_ID,
905
- updateStrategy: "appVersion"
906
- })]]);
907
- });
908
- it.each([{
909
- label: "a native rejection without a failure class",
910
- fail: () => mocks.stageBundle.mockRejectedValueOnce(Object.assign(new Error("Release catalog selection is stale"), {
911
- code: "UNKNOWN_ERROR"
912
- }))
913
- }, {
914
- label: "a selection that became stale",
915
- fail: () => mocks.isReleaseSelectionCurrent.mockReturnValueOnce(false)
916
- }])("does not report $label as an update failure", async ({
917
- fail
918
- }) => {
919
- const {
920
- checkForUpdate
921
- } = await import("./checkForUpdate");
922
- const events = await recordPluginEvents();
923
- const {
924
- client
925
- } = createClient();
926
- const result = await checkForUpdate({
927
- client,
928
- updateStrategy: "appVersion"
929
- });
930
- fail();
931
- await expect(result.updateBundle()).rejects.toThrow();
932
- expect(events.map(([name]) => name)).toEqual(["onUpdateCheck"]);
933
- });
934
- });
935
- //# sourceMappingURL=checkForUpdate.releaseCatalog.spec.js.map