expo-updates
Version:
Fetches and manages remotely-hosted assets and updates to your app's JS bundle.
104 lines (85 loc) • 3.79 kB
text/typescript
import { by, device, element, waitFor } from 'detox';
import jestExpect from 'expect';
import Server from './utils/server';
import Update from './utils/update';
const projectRoot = process.env.PROJECT_ROOT || process.cwd();
const platform = device.getPlatform();
const protocolVersion = 1;
const testElementValueAsync = async (testID: string) => {
const attributes: any = await element(by.id(testID)).getAttributes();
return attributes?.text || '';
};
const waitForAppToBecomeVisible = async () => {
await waitFor(element(by.id('updateString')))
.toBeVisible()
.withTimeout(3000);
};
describe('Error recovery tests', () => {
afterEach(async () => {
await device.uninstallApp();
Server.stop();
});
it('downloads new update before launching, but launches the last non-crashing update', async () => {
Server.start(Update.serverPort, protocolVersion, 1000);
await Server.serveSignedDirective(Update.getNoUpdateAvailableDirective(), projectRoot);
await device.installApp();
await device.launchApp({
newInstance: true,
});
const request1 = await Server.waitForUpdateRequest(10000);
const request1CurrentUpdateId = request1.headers['expo-current-update-id'];
const request1RecentFailedUpdateIds = request1.headers['expo-recent-failed-update-ids'];
const embeddedUpdateId = request1.headers['expo-embedded-update-id'];
jestExpect(embeddedUpdateId).toBeTruthy();
jestExpect(request1RecentFailedUpdateIds).toBeUndefined();
jestExpect(request1CurrentUpdateId).toEqual(embeddedUpdateId);
await waitForAppToBecomeVisible();
await device.terminateApp();
const bundleFilename = 'bundle1.js';
const newNotifyString = 'test-update-crashing';
const hash = await Update.copyBundleToStaticFolder(
projectRoot,
bundleFilename,
newNotifyString,
platform
);
const manifest = Update.getUpdateManifestForBundleFilename(
new Date(),
hash,
'test-update-crashing-key',
bundleFilename,
[],
projectRoot
);
const failingId = manifest.id;
await Server.serveSignedManifest(manifest, projectRoot);
// launch app for error recovery
try {
// Detox on Android may timeout from waiting idling resources because Detox doesn't support reloading the app under the hood
await device.launchApp({
newInstance: true,
});
} catch {}
// we don't check current update ID header or failed update IDs header since the behavior for this request is not defined
// (we don't guarantee current update to be set during a crash or the launch failure to have been registered yet)
const request2 = await Server.waitForUpdateRequest(10000);
const request2EmbeddedUpdateId = request2.headers['expo-embedded-update-id'];
jestExpect(embeddedUpdateId).toEqual(request2EmbeddedUpdateId);
await device.terminateApp();
// relaunch, it should launch the embedded update since the update being served failed to launch
await device.launchApp({
newInstance: true,
});
const request3 = await Server.waitForUpdateRequest(10000);
const request3CurrentUpdateId = request3.headers['expo-current-update-id'];
const request3EmbeddedUpdateId = request3.headers['expo-embedded-update-id'];
const request3RecentFailedUpdateIds = request3.headers['expo-recent-failed-update-ids'];
jestExpect(embeddedUpdateId).toEqual(request3EmbeddedUpdateId);
jestExpect(embeddedUpdateId).toEqual(request3CurrentUpdateId);
jestExpect(request3RecentFailedUpdateIds).toEqual(`"${failingId}"`);
await waitForAppToBecomeVisible();
const message = await testElementValueAsync('updateString');
jestExpect(message).toBe('test');
await device.terminateApp();
});
});