@bravemobile/react-native-code-push
Version:
React Native plugin for the CodePush service
284 lines (238 loc) • 14.7 kB
JavaScript
import { SemverVersioning } from "./SemverVersioning";
describe('Semver Versioning Test', () => {
const MOCK_INFOS = { downloadUrl: '', packageHash: '' }
// When major version is released, it must be considered like below
const FIRST_RELEASE_INFO = { enabled: true, mandatory: false, ...MOCK_INFOS };
describe('findLatestRelease', () => {
it('should throw error when there is no releases', () => {
const RELEASED_BUNDLES = {}
expect(() => new SemverVersioning(RELEASED_BUNDLES).findLatestRelease())
.toThrow("There is no latest release.")
})
it('should return latest release', () => {
const RELEASED_BUNDLES = {
'1.0.0': { enabled: true, mandatory: false, downloadUrl: 'R1', packageHash: 'P1' },
'1.1.0': { enabled: true, mandatory: false, downloadUrl: 'R2', packageHash: 'P2' },
'1.1.1': { enabled: true, mandatory: true, downloadUrl: 'R3', packageHash: 'P3' },
};
expect(new SemverVersioning(RELEASED_BUNDLES).findLatestRelease()).toEqual([
'1.1.1',
{ enabled: true, mandatory: true, downloadUrl: 'R3', packageHash: 'P3' }
])
})
it('should ignore not-enabled bundles and return latest release', () => {
const RELEASED_BUNDLES_1 = {
'1.0.0': { enabled: true, mandatory: false, downloadUrl: 'R1', packageHash: 'P1' },
'1.1.0': { enabled: false, mandatory: false, downloadUrl: 'R2', packageHash: 'P2' },
};
const RELEASED_BUNDLES_2 = {
'1.0.0': { enabled: true, mandatory: false, downloadUrl: 'R1', packageHash: 'P1' },
'1.1.0': { enabled: false, mandatory: false, downloadUrl: 'R2', packageHash: 'P2' },
'1.1.1': { enabled: true, mandatory: true, downloadUrl: 'R3', packageHash: 'P3' },
};
expect(new SemverVersioning(RELEASED_BUNDLES_1).findLatestRelease()).toEqual([
'1.0.0',
{ enabled: true, mandatory: false, downloadUrl: 'R1', packageHash: 'P1' }
])
expect(new SemverVersioning(RELEASED_BUNDLES_2).findLatestRelease()).toEqual([
'1.1.1',
{ enabled: true, mandatory: true, downloadUrl: 'R3', packageHash: 'P3' }
])
})
it('should return the previous enabled release if the latest release is not a rollout target', () => {
const RELEASED_BUNDLES = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: false, mandatory: false, ...MOCK_INFOS }, // not enabled
'1.2.0': { enabled: true, mandatory: false, ...MOCK_INFOS, rollout: 30 },
};
const LATEST_IS_ROLLOUT_TARGET = false;
const versioning = new SemverVersioning(RELEASED_BUNDLES);
versioning.setIsLatestReleaseInRollout(LATEST_IS_ROLLOUT_TARGET);
const [latestVersion] = versioning.findLatestRelease();
expect(latestVersion).toEqual('1.0.0');
})
it('should return the latest release if the latest release is a rollout target', () => {
const RELEASED_BUNDLES = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.2.0': { enabled: true, mandatory: false, ...MOCK_INFOS, rollout: 30 },
};
const LATEST_IS_ROLLOUT_TARGET = true;
const versioning = new SemverVersioning(RELEASED_BUNDLES);
versioning.setIsLatestReleaseInRollout(LATEST_IS_ROLLOUT_TARGET);
const [latestVersion] = versioning.findLatestRelease();
expect(latestVersion).toEqual('1.2.0');
})
})
describe('checkIsMandatory', () => {
describe('not-mandatory cases', () => {
it('should consider not-mandatory when the first major version is released', () => {
const RUNTIME_VERSION = '1.0.0';
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(false);
});
it('should consider not-mandatory when latest version is running', () => {
const RUNTIME_VERSION = '1.1.1';
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(false);
});
it('should consider not-mandatory when only not-mandatory version is released', () => {
const RUNTIME_VERSION = '1.0.0';
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(false);
});
it('should consider not-mandatory when only not-mandatory version is released after current runtime version', () => {
const RUNTIME_VERSION = '1.0.1';
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.0.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(false);
});
})
describe('mandatory cases', () => {
it('should consider mandatory when mandatory release exists', () => {
const RUNTIME_VERSION = '1.0.0';
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.0.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(true);
});
it("should consider mandatory if there's a mandatory release between the runtime version and the latest", () => {
const RUNTIME_VERSION = '1.0.0'
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.2.0': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.3.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
}
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(RUNTIME_VERSION)).toBe(true);
})
it('should consider mandatory when latest version < current runtime version (ROLLBACK)', () => {
const RELEASED_BUNDLES = {
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
const currentVersion = '1.2.0'
expect(new SemverVersioning(RELEASED_BUNDLES).shouldRollback(currentVersion)).toBe(true)
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory(currentVersion)).toBe(true)
})
})
describe('scenario test', () => {
it('Major Release > Mandatory > Not-mandatory > Mandatory > Not-mandatory', () => {
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.0.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.2.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.0.0')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.0.1')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.1.0')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.1.1')).toBe(false);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.2.0')).toBe(false);
});
it('When having not-enabled releases', () => {
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.0.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.1.0': { enabled: false, mandatory: false, ...MOCK_INFOS },
'1.1.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.2.0': { enabled: false, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.0.0')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.0.1')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.1.0')).toBe(true);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.1.1')).toBe(false);
expect(new SemverVersioning(RELEASED_BUNDLES).checkIsMandatory('1.2.0')).toBe(true);
});
it('When having not-enabled releases and latest mandatory version is not a rollout target', () => {
const RELEASED_BUNDLES = {
'1.0.0': FIRST_RELEASE_INFO,
'1.0.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.1.0': { enabled: false, mandatory: false, ...MOCK_INFOS },
'1.1.1': { enabled: true, mandatory: true, ...MOCK_INFOS },
'1.2.0': { enabled: true, mandatory: true, ...MOCK_INFOS, rollout: 30 },
};
const LATEST_IS_ROLLOUT_TARGET = false;
const versioning = new SemverVersioning(RELEASED_BUNDLES);
versioning.setIsLatestReleaseInRollout(LATEST_IS_ROLLOUT_TARGET);
expect(versioning.checkIsMandatory('1.0.0')).toBe(true); // update to 1.1.1
expect(versioning.checkIsMandatory('1.0.1')).toBe(true); // update to 1.1.1
expect(versioning.checkIsMandatory('1.1.0')).toBe(true); // update to 1.1.1
expect(versioning.checkIsMandatory('1.1.1')).toBe(false); // up to date
expect(versioning.checkIsMandatory('1.2.0')).toBe(true); // rollback target is treated as mandatory
})
})
})
describe('shouldRollbackToBinary', () => {
it('should return false if it is not required to rollback', () => {
const RELEASED_BUNDLES_1 = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
const RELEASED_BUNDLES_2 = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.2.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES_1).shouldRollbackToBinary('1.0.0')).toBe(false)
expect(new SemverVersioning(RELEASED_BUNDLES_2).shouldRollbackToBinary('1.1.0')).toBe(false)
})
it('should return true if the destination version is the latest major version', () => {
const RELEASED_BUNDLES_1 = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: false, mandatory: false, ...MOCK_INFOS },
'1.2.0': { enabled: false, mandatory: false, ...MOCK_INFOS },
};
const RELEASED_BUNDLES_2 = {
'1.2.0-rc.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES_1).shouldRollbackToBinary('1.2.0')).toBe(true)
expect(new SemverVersioning(RELEASED_BUNDLES_2).shouldRollbackToBinary('1.2.0-rc.2')).toBe(true)
})
it('should return false if the destination version is not the latest major version', () => {
const RELEASED_BUNDLES_1 = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
const RELEASED_BUNDLES_2 = {
'1.2.0-rc.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.2.0-rc.1': { enabled: true, mandatory: false, ...MOCK_INFOS },
};
expect(new SemverVersioning(RELEASED_BUNDLES_1).shouldRollbackToBinary('1.2.0')).toBe(false)
expect(new SemverVersioning(RELEASED_BUNDLES_2).shouldRollbackToBinary('1.2.0-rc.2')).toBe(false)
})
it ('should return true if the latest release is not a rollout target', () => {
const RELEASED_BUNDLES = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS, rollout: 30 },
};
const LATEST_IS_ROLLOUT_TARGET = false;
const versioning = new SemverVersioning(RELEASED_BUNDLES);
versioning.setIsLatestReleaseInRollout(LATEST_IS_ROLLOUT_TARGET);
// If the latest release was a rollout target and the rollout value is later reduced, the app might run on version 1.1.0.
expect(versioning.shouldRollbackToBinary('1.1.0')).toBe(true);
})
it ('should return false if the latest release and the previous release are both rollout targets', () => {
const RELEASED_BUNDLES = {
'1.0.0': { enabled: true, mandatory: false, ...MOCK_INFOS },
'1.1.0': { enabled: true, mandatory: false, ...MOCK_INFOS, rollout: 30 },
'1.2.0': { enabled: true, mandatory: false, ...MOCK_INFOS, rollout: 30 },
};
const LATEST_IS_ROLLOUT_TARGET = true;
const versioning = new SemverVersioning(RELEASED_BUNDLES);
versioning.setIsLatestReleaseInRollout(LATEST_IS_ROLLOUT_TARGET);
expect(versioning.shouldRollbackToBinary('1.0.0')).toBe(false); // update to 1.1.0
})
})
})