Files
self/app/scripts/version-manager.test.cjs
Justin Hernandez e01ec188af code rabbit feedback for staging auto deploy logic (#1255)
* code rabbit feedback for staging auto deploy logic

* fix jest test

* cr feedback

* workflow fixes

* fix tests

* restore cache
2025-10-17 07:58:02 -07:00

317 lines
9.7 KiB
JavaScript

// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
/**
* @jest-environment node
*
* SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
* SPDX-License-Identifier: BUSL-1.1
* NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
*/
/**
* Unit tests for version-manager.cjs
*
* This file is only meant to be run with Jest.
*/
const path = require('path');
// Mock file system operations - data
const mockPackageJson = { version: '1.2.3' };
const mockVersionJson = {
ios: { build: 100, lastDeployed: '2024-01-01T00:00:00Z' },
android: { build: 200, lastDeployed: '2024-01-01T00:00:00Z' },
};
// Use manual mocking instead of jest.mock to avoid hoisting issues
const fs = require('fs');
// Store originals for restore
const originalReadFileSync = fs.readFileSync;
const originalWriteFileSync = fs.writeFileSync;
const originalExistsSync = fs.existsSync;
const originalAppendFileSync = fs.appendFileSync;
// Setup mocks before importing the module
function setupMocks() {
fs.readFileSync = function (filePath, encoding) {
if (filePath.includes('package.json')) {
return JSON.stringify(mockPackageJson);
}
if (filePath.includes('version.json')) {
return JSON.stringify(mockVersionJson);
}
return originalReadFileSync(filePath, encoding);
};
fs.writeFileSync = function () {};
fs.existsSync = function () {
return true;
};
fs.appendFileSync = function () {};
}
function restoreMocks() {
fs.readFileSync = originalReadFileSync;
fs.writeFileSync = originalWriteFileSync;
fs.existsSync = originalExistsSync;
fs.appendFileSync = originalAppendFileSync;
}
// Setup mocks before requiring the module
setupMocks();
// Import module after mocks are set up
const versionManager = require('./version-manager.cjs');
describe('version-manager', () => {
beforeEach(() => {
// Reset mock data
mockPackageJson.version = '1.2.3';
mockVersionJson.ios.build = 100;
mockVersionJson.android.build = 200;
});
afterAll(() => {
restoreMocks();
});
describe('getVersionInfo', () => {
it('should return current version information', () => {
const info = versionManager.getVersionInfo();
expect(info.version).toBe('1.2.3');
expect(info.iosBuild).toBe(100);
expect(info.androidBuild).toBe(200);
});
});
describe('bumpVersion', () => {
it('should bump major version correctly', () => {
const result = versionManager.bumpVersion('major', 'both');
expect(result.version).toBe('2.0.0');
expect(result.iosBuild).toBe(101);
expect(result.androidBuild).toBe(201);
});
it('should bump minor version correctly', () => {
const result = versionManager.bumpVersion('minor', 'both');
expect(result.version).toBe('1.3.0');
expect(result.iosBuild).toBe(101);
expect(result.androidBuild).toBe(201);
});
it('should bump patch version correctly', () => {
const result = versionManager.bumpVersion('patch', 'both');
expect(result.version).toBe('1.2.4');
expect(result.iosBuild).toBe(101);
expect(result.androidBuild).toBe(201);
});
it('should bump build numbers only', () => {
const result = versionManager.bumpVersion('build', 'both');
expect(result.version).toBe('1.2.3');
expect(result.iosBuild).toBe(101);
expect(result.androidBuild).toBe(201);
});
it('should respect platform parameter (ios only)', () => {
const result = versionManager.bumpVersion('build', 'ios');
expect(result.version).toBe('1.2.3');
expect(result.iosBuild).toBe(101);
expect(result.androidBuild).toBe(200); // unchanged
});
it('should respect platform parameter (android only)', () => {
const result = versionManager.bumpVersion('build', 'android');
expect(result.version).toBe('1.2.3');
expect(result.iosBuild).toBe(100); // unchanged
expect(result.androidBuild).toBe(201);
});
it('should throw on invalid bump type', () => {
expect(() => versionManager.bumpVersion('invalid', 'both')).toThrow(
/Invalid bump type/,
);
});
it('should throw on invalid platform', () => {
expect(() => versionManager.bumpVersion('build', 'invalid')).toThrow(
/Invalid platform/,
);
});
it('should handle version with major bump resetting minor and patch', () => {
mockPackageJson.version = '2.5.8';
const result = versionManager.bumpVersion('major', 'both');
expect(result.version).toBe('3.0.0');
});
it('should handle version with minor bump resetting patch', () => {
mockPackageJson.version = '2.5.8';
const result = versionManager.bumpVersion('minor', 'both');
expect(result.version).toBe('2.6.0');
});
});
describe('applyVersions', () => {
it('should reject invalid version format - not semver', () => {
expect(() => versionManager.applyVersions('invalid', 1, 1)).toThrow(
/Invalid version format/,
);
});
it('should reject invalid version format - two parts', () => {
expect(() => versionManager.applyVersions('1.2', 1, 1)).toThrow(
/Invalid version format/,
);
});
it('should reject invalid version format - four parts', () => {
expect(() => versionManager.applyVersions('1.2.3.4', 1, 1)).toThrow(
/Invalid version format/,
);
});
it('should reject invalid version format - empty string', () => {
expect(() => versionManager.applyVersions('', 1, 1)).toThrow(
/Invalid version format/,
);
});
it('should reject invalid version format - null', () => {
expect(() => versionManager.applyVersions(null, 1, 1)).toThrow(
/Invalid version format/,
);
});
it('should reject invalid iOS build number - zero', () => {
expect(() => versionManager.applyVersions('1.2.3', 0, 1)).toThrow(
/Invalid iOS build/,
);
});
it('should reject invalid iOS build number - negative', () => {
expect(() => versionManager.applyVersions('1.2.3', -1, 1)).toThrow(
/Invalid iOS build/,
);
});
it('should reject invalid iOS build number - non-numeric string', () => {
expect(() => versionManager.applyVersions('1.2.3', 'abc', 1)).toThrow(
/Invalid iOS build/,
);
});
it('should reject invalid iOS build number - float', () => {
expect(() => versionManager.applyVersions('1.2.3', 1.5, 1)).toThrow(
/Invalid iOS build/,
);
});
it('should reject invalid Android build number - zero', () => {
expect(() => versionManager.applyVersions('1.2.3', 1, 0)).toThrow(
/Invalid Android build/,
);
});
it('should reject invalid Android build number - negative', () => {
expect(() => versionManager.applyVersions('1.2.3', 1, -1)).toThrow(
/Invalid Android build/,
);
});
it('should reject invalid Android build number - non-numeric string', () => {
expect(() => versionManager.applyVersions('1.2.3', 1, 'xyz')).toThrow(
/Invalid Android build/,
);
});
it('should reject invalid Android build number - float', () => {
expect(() => versionManager.applyVersions('1.2.3', 1, 2.5)).toThrow(
/Invalid Android build/,
);
});
it('should accept string build numbers that parse to integers', () => {
expect(() =>
versionManager.applyVersions('1.2.3', '100', '200'),
).not.toThrow();
});
it('should accept large build numbers', () => {
expect(() =>
versionManager.applyVersions('1.2.3', 99999, 88888),
).not.toThrow();
});
it('should write correct values to files', () => {
// Track write calls
const writeCalls = [];
fs.writeFileSync = function (filePath, content) {
writeCalls.push({ filePath, content });
};
versionManager.applyVersions('2.0.0', 150, 250);
// Verify writes occurred
expect(writeCalls.length).toBe(2);
// Find and verify package.json write
const packageWrite = writeCalls.find(call =>
call.filePath.includes('package.json'),
);
expect(packageWrite).toBeDefined();
const updatedPackage = JSON.parse(packageWrite.content);
expect(updatedPackage.version).toBe('2.0.0');
// Find and verify version.json write
const versionWrite = writeCalls.find(call =>
call.filePath.includes('version.json'),
);
expect(versionWrite).toBeDefined();
const updatedVersion = JSON.parse(versionWrite.content);
expect(updatedVersion.ios.build).toBe(150);
expect(updatedVersion.android.build).toBe(250);
});
});
describe('readPackageJson', () => {
it('should read and parse package.json', () => {
const pkg = versionManager.readPackageJson();
expect(pkg.version).toBe('1.2.3');
});
it('should throw error if file does not exist', () => {
const originalExists = fs.existsSync;
fs.existsSync = function () {
return false;
};
expect(() => versionManager.readPackageJson()).toThrow(
/package.json not found/,
);
fs.existsSync = originalExists;
});
});
describe('readVersionJson', () => {
it('should read and parse version.json', () => {
const version = versionManager.readVersionJson();
expect(version.ios.build).toBe(100);
expect(version.android.build).toBe(200);
});
it('should throw error if file does not exist', () => {
const originalExists = fs.existsSync;
fs.existsSync = function () {
return false;
};
expect(() => versionManager.readVersionJson()).toThrow(
/version.json not found/,
);
fs.existsSync = originalExists;
});
});
});