Files
self/scripts/tests/check-package-versions.test.mjs
Justin Hernandez 590f188f3c [SELF-676] feat: upgrade React Native from 0.75.4 to 0.76.9 (#943)
* chore: upgrade build tooling to Node 22 and AGP 8.6

* chore: upgrade react-native to 0.76.9

* update lock files and formatting

* fix path

* fix: handle hermes-engine cache mismatch in CI after React Native upgrade

- Add fallback logic to run 'pod update hermes-engine' when pod install fails
- This resolves CocoaPods cache issues that occur after React Native version upgrades
- Fixes CI pipeline failures on codex/update-core-tooling-for-react-native-upgrade branch

* fix: improve hermes-engine cache handling in CI

- Preemptively clear CocoaPods cache before pod install
- This prevents dependency analysis failures that occur when cached podspecs conflict
- Addresses the root cause: cache conflicts during 'Analyzing dependencies' phase
- Keeps fallback logic for additional safety

* fix: handle hermes-engine cache in mobile-bundle-analysis workflow

- Add pod-install-with-cache-fix.sh script to handle hermes-engine cache conflicts
- Update install-app:setup script to use the new cache fix approach
- This fixes the mobile-bundle-analysis.yml workflow failures after React Native upgrade
- Proactively clears CocoaPods cache and has fallback for hermes-engine updates

* formatting

* fix: robust hermes-engine cache handling in CI workflows

- Apply comprehensive cache clearing to mobile-ci.yml and mobile-e2e.yml
- Pre-emptively run 'pod update hermes-engine' before pod install
- Clear multiple cache locations to handle CI environment differences
- This prevents 'hermes-engine differs from Pods/Local Podspecs' errors
- Fixes all workflows affected by React Native 0.76.9 upgrade cache issues

* fixes

* clean up

* update lock files

* fix tests

* sort

* fixes

* fix ci

* fix deployment target

* android fixes

* upgrade fix

* fixes

* fix: streamline mobile CI build and caching (#946)

* fix: streamline mobile CI build and caching

* Enable mobile E2E tests on codex/fix-mobile-ci-workflow-errors branch

* test

* simplify and fix path

* workflow fixes

* fix loading on 0.76.9

* clean up unnecessary comments

* fix readme

* finalize upgrade to 0.76.9

* fix android build and upgrade

* fix bundler caching

* download cli to fix "yarn start" issues

* fix cli build erorr

* fix script path

* better path

* abstract build step to prevent race condition

* fixes

* better cache

* fix corepack build error

* update lock

* update lock

* add yarn cache to workflows

* fix test building

* ci caching improvements

* fix common type check

* fix common ci

* better mobile sdk alpha building logic

* chore: speed up mobile e2e workflow (#962)

* chore: speed up mobile e2e workflow

* chore: disable android e2e job

* chore: speed up ios build

* fix: bundle js for ios debug build

* fix e2e
2025-08-26 20:27:51 -07:00

321 lines
8.7 KiB
JavaScript

#!/usr/bin/env node
import { test, describe, expect, beforeAll, afterAll } from 'vitest';
import { promises as fs } from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import { fileURLToPath } from 'url';
// Resolve paths relative to this test file
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const testDir = path.join(__dirname, 'fixtures');
const scriptPath = path.resolve(__dirname, '..', 'check-package-versions.mjs');
describe('check-package-versions', () => {
beforeAll(async () => {
// Create test fixtures directory
await fs.mkdir(testDir, { recursive: true });
});
afterAll(async () => {
// Cleanup
await fs.rm(testDir, { recursive: true, force: true });
});
test('should pass when all versions are consistent', async () => {
// Create consistent package.json files
const consistentPkg = {
name: 'test-package',
version: '1.0.0',
dependencies: {
ethers: '^6.13.5',
'node-forge': '^1.3.1',
'poseidon-lite': '^0.3.0',
snarkjs: '^0.7.5',
react: '^18.3.1',
'react-native': '0.76.9',
'@tamagui/config': '1.126.14',
'@tamagui/lucide-icons': '1.126.14',
typescript: '^5.9.2',
prettier: '^3.5.3',
'@types/node': '^22.0.0',
},
engines: { node: '>=22 <23' },
};
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(consistentPkg, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(consistentPkg, null, 2),
);
// Run script in test directory
const result = execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect(result).toContain(
'✅ All package versions are consistent across the monorepo!',
);
});
test('should detect other package mismatches', async () => {
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
const pkg1 = {
dependencies: {
prettier: '^3.5.3',
typescript: '^5.9.2',
},
};
const pkg2 = {
dependencies: {
prettier: '^3.3.3',
typescript: '^5.8.0',
},
};
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(pkg1, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(pkg2, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('📦 OTHER VERSION MISMATCHES:');
expect(error.stdout).toContain('prettier:');
expect(error.stdout).toContain('typescript:');
}
});
test('should fail when critical packages have different versions', async () => {
const pkg1 = {
name: 'test-package-1',
dependencies: {
ethers: '^6.11.0',
'node-forge': '^1.3.1',
},
};
const pkg2 = {
name: 'test-package-2',
dependencies: {
ethers: '^6.13.5',
'node-forge': 'github:remicolin/forge',
},
};
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(pkg1, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(pkg2, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('🚨 CRITICAL VERSION MISMATCHES:');
expect(error.stdout).toContain('ethers:');
expect(error.stdout).toContain('node-forge:');
}
});
test('should detect workflow version mismatches', async () => {
// Create workflow with different Node.js version
const workflowContent = `
name: Test
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: 20
`;
await fs.mkdir(path.join(testDir, '.github', 'workflows'), {
recursive: true,
});
await fs.writeFile(
path.join(testDir, '.github', 'workflows', 'test.yml'),
workflowContent,
);
// Create package.json with Node 22 engine
const pkg = {
engines: { node: '>=22 <23' },
};
await fs.writeFile(
path.join(testDir, 'package.json'),
JSON.stringify(pkg, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('Expected: >=22 <23');
expect(error.stdout).toContain('Found: 20');
}
});
test('should detect React Native ecosystem inconsistencies', async () => {
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
const pkg1 = {
dependencies: {
react: '^18.3.1',
'react-native': '0.76.9',
},
};
const pkg2 = {
dependencies: {
react: '^18.0.0',
'react-native': '0.74.0',
},
};
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(pkg1, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(pkg2, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('react:');
expect(error.stdout).toContain('react-native:');
}
});
test('should detect Tamagui version inconsistencies', async () => {
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
const pkg1 = {
dependencies: {
'@tamagui/config': '1.126.14',
'@tamagui/lucide-icons': '1.126.14',
},
};
const pkg2 = {
dependencies: {
'@tamagui/config': '1.129.3',
'@tamagui/lucide-icons': '1.129.3',
},
};
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(pkg1, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(pkg2, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('@tamagui/config:');
expect(error.stdout).toContain('@tamagui/lucide-icons:');
}
});
test('should handle missing files gracefully', async () => {
// Clean up any leftover files from previous tests
await fs.rm(testDir, { recursive: true, force: true });
await fs.mkdir(testDir, { recursive: true });
// Empty directory should not crash
const result = execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect(result).toContain(
'✅ All package versions are consistent across the monorepo!',
);
});
test('should provide helpful fix instructions', async () => {
await fs.mkdir(path.join(testDir, 'pkg1'), { recursive: true });
await fs.mkdir(path.join(testDir, 'pkg2'), { recursive: true });
const pkg1 = {
dependencies: { ethers: '^6.11.0' },
};
const pkg2 = {
dependencies: { ethers: '^6.13.5' },
};
await fs.writeFile(
path.join(testDir, 'pkg1', 'package.json'),
JSON.stringify(pkg1, null, 2),
);
await fs.writeFile(
path.join(testDir, 'pkg2', 'package.json'),
JSON.stringify(pkg2, null, 2),
);
try {
execSync(`node ${scriptPath}`, {
cwd: testDir,
encoding: 'utf8',
});
expect.fail('Should have thrown an error');
} catch (error) {
expect(error.status).toBe(1);
expect(error.stdout).toContain('📋 Mismatched Packages:');
expect(error.stdout).toContain('🚨 Critical:');
expect(error.stdout).toContain('• ethers:');
}
});
});