Skip to content

Commit 714e108

Browse files
committed
add beforeReload hook
1 parent a939db7 commit 714e108

3 files changed

Lines changed: 116 additions & 3 deletions

File tree

src/__tests__/client.test.ts

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ const createJsonResponse = (payload: unknown) =>
1313
const setupClientMocks = ({
1414
isFirstTime = false,
1515
markSuccess = mock(() => {}),
16+
reloadUpdate = mock(() => Promise.resolve()),
17+
setNeedUpdate = mock(() => Promise.resolve()),
1618
downloadPatchFromPpk = mock(() => Promise.resolve()),
1719
downloadPatchFromPackage = mock(() => Promise.resolve()),
1820
downloadFullUpdate = mock(() => Promise.resolve()),
21+
restartApp = mock(() => Promise.resolve()),
1922
}: {
2023
isFirstTime?: boolean;
2124
markSuccess?: ReturnType<typeof mock>;
25+
reloadUpdate?: ReturnType<typeof mock>;
26+
setNeedUpdate?: ReturnType<typeof mock>;
2227
downloadPatchFromPpk?: ReturnType<typeof mock>;
2328
downloadPatchFromPackage?: ReturnType<typeof mock>;
2429
downloadFullUpdate?: ReturnType<typeof mock>;
30+
restartApp?: ReturnType<typeof mock>;
2531
} = {}) => {
2632
(globalThis as any).__DEV__ = false;
2733

@@ -42,13 +48,13 @@ const setupClientMocks = ({
4248
mock.module('../core', () => ({
4349
PushyModule: {
4450
markSuccess,
45-
reloadUpdate: mock(() => Promise.resolve()),
46-
setNeedUpdate: mock(() => Promise.resolve()),
51+
reloadUpdate,
52+
setNeedUpdate,
4753
downloadPatchFromPpk,
4854
downloadPatchFromPackage,
4955
downloadFullUpdate,
5056
downloadAndInstallApk: mock(() => Promise.resolve()),
51-
restartApp: mock(() => Promise.resolve()),
57+
restartApp,
5258
},
5359
buildTime: '2023-01-01',
5460
cInfo: {
@@ -283,4 +289,78 @@ describe('Pushy server config', () => {
283289
}),
284290
);
285291
});
292+
293+
test('waits for beforeReload before switching version', async () => {
294+
const calls: string[] = [];
295+
const reloadUpdate = mock(() => {
296+
calls.push('reloadUpdate');
297+
return Promise.resolve();
298+
});
299+
const beforeReload = mock(async (context: any) => {
300+
calls.push('beforeReload');
301+
expect(context).toEqual({
302+
type: 'switchVersion',
303+
hash: 'next-hash',
304+
});
305+
});
306+
setupClientMocks({ reloadUpdate });
307+
308+
const { Pushy, sharedState } = await importFreshClient('before-reload-switch-version');
309+
sharedState.downloadedHash = 'next-hash';
310+
const client = new Pushy({
311+
appKey: 'demo-app',
312+
beforeReload,
313+
});
314+
315+
await client.switchVersion('next-hash');
316+
317+
expect(calls).toEqual(['beforeReload', 'reloadUpdate']);
318+
expect(beforeReload).toHaveBeenCalledTimes(1);
319+
expect(reloadUpdate).toHaveBeenCalledWith({ hash: 'next-hash' });
320+
});
321+
322+
test('skips switching version when beforeReload returns false', async () => {
323+
const reloadUpdate = mock(() => Promise.resolve());
324+
const beforeReload = mock(() => false);
325+
setupClientMocks({ reloadUpdate });
326+
327+
const { Pushy, sharedState } = await importFreshClient('before-reload-skip-switch');
328+
sharedState.downloadedHash = 'next-hash';
329+
const client = new Pushy({
330+
appKey: 'demo-app',
331+
beforeReload,
332+
});
333+
334+
await client.switchVersion('next-hash');
335+
336+
expect(beforeReload).toHaveBeenCalledTimes(1);
337+
expect(reloadUpdate).not.toHaveBeenCalled();
338+
expect(sharedState.applyingUpdate).toBe(false);
339+
});
340+
341+
test('calls beforeReload before restartApp', async () => {
342+
const calls: string[] = [];
343+
const restartApp = mock(() => {
344+
calls.push('restartApp');
345+
return Promise.resolve();
346+
});
347+
const beforeReload = mock(async (context: any) => {
348+
calls.push('beforeReload');
349+
expect(context).toEqual({
350+
type: 'restartApp',
351+
});
352+
});
353+
setupClientMocks({ restartApp });
354+
355+
const { Pushy } = await importFreshClient('before-reload-restart-app');
356+
const client = new Pushy({
357+
appKey: 'demo-app',
358+
beforeReload,
359+
});
360+
361+
await client.restartApp();
362+
363+
expect(calls).toEqual(['beforeReload', 'restartApp']);
364+
expect(restartApp).toHaveBeenCalled();
365+
});
286366
});

src/client.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from './core';
1919
import { PermissionsAndroid } from './permissions';
2020
import {
21+
BeforeReloadContext,
2122
CheckResult,
2223
ClientOptions,
2324
EventType,
@@ -218,6 +219,18 @@ export class Pushy {
218219
log('afterCheckUpdate failed:', error?.message || error);
219220
});
220221
};
222+
runBeforeReload = async (context: BeforeReloadContext) => {
223+
const { beforeReload } = this.options;
224+
if (!beforeReload) {
225+
return true;
226+
}
227+
const shouldReload = await beforeReload(context);
228+
if (shouldReload === false) {
229+
log('beforeReload returned false, skipping reload');
230+
return false;
231+
}
232+
return true;
233+
};
221234
getCheckUrl = (endpoint: string) => {
222235
return `${endpoint}/checkUpdate/${this.options.appKey}`;
223236
};
@@ -325,6 +338,15 @@ export class Pushy {
325338
if (assertHash(hash) && !sharedState.applyingUpdate) {
326339
log(`switchVersion: ${hash}`);
327340
sharedState.applyingUpdate = true;
341+
try {
342+
if (!(await this.runBeforeReload({ type: 'switchVersion', hash }))) {
343+
sharedState.applyingUpdate = false;
344+
return;
345+
}
346+
} catch (e) {
347+
sharedState.applyingUpdate = false;
348+
throw e;
349+
}
328350
return PushyModule.reloadUpdate({ hash });
329351
}
330352
};
@@ -668,6 +690,9 @@ export class Pushy {
668690
}
669691
};
670692
restartApp = async () => {
693+
if (!(await this.runBeforeReload({ type: 'restartApp' }))) {
694+
return;
695+
}
671696
return PushyModule.restartApp();
672697
};
673698
}

src/type.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ export interface UpdateServerConfig {
8888
queryUrls?: string[];
8989
}
9090

91+
export interface BeforeReloadContext {
92+
type: 'switchVersion' | 'restartApp';
93+
hash?: string;
94+
}
95+
9196
export interface ClientOptions {
9297
appKey: string;
9398
server?: UpdateServerConfig;
@@ -109,6 +114,9 @@ export interface ClientOptions {
109114
afterCheckUpdate?: (state: UpdateCheckState) => Promise<void> | void;
110115
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean> | boolean;
111116
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean> | boolean;
117+
beforeReload?: (
118+
context: BeforeReloadContext,
119+
) => Promise<boolean | void> | boolean | void;
112120
onPackageExpired?: (info: CheckResult) => Promise<boolean> | boolean;
113121
overridePackageVersion?: string;
114122
}

0 commit comments

Comments
 (0)