fix(tests): Use unique test run IDs and add S3 cleanup in test helpers to avoid cross-run conflicts

This commit is contained in:
2025-11-27 12:41:38 +00:00
parent 58a21a6bbb
commit eb91a3f75b
5 changed files with 151 additions and 49 deletions

View File

@@ -6,7 +6,7 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { tapNodeTools } from '@git.zone/tstest/tapbundle_serverside';
import { SmartRegistry } from '../ts/index.js';
import { createTestRegistry, createTestTokens, createComposerZip } from './helpers/registry.js';
import { createTestRegistry, createTestTokens, createComposerZip, generateTestRunId } from './helpers/registry.js';
import type { IRequestContext, IResponse } from '../ts/core/interfaces.core.js';
import * as http from 'http';
import * as url from 'url';
@@ -21,6 +21,11 @@ let registryPort: number;
let composerToken: string;
let testDir: string;
let composerHome: string;
let hasComposer = false;
// Unique test run ID to avoid conflicts between test runs
const testRunId = generateTestRunId();
const testPackageName = `testvendor/test-pkg-${testRunId}`;
/**
* Create HTTP server wrapper around SmartRegistry
@@ -235,12 +240,11 @@ tap.test('Composer CLI: should verify composer is installed', async () => {
try {
const result = await tapNodeTools.runCommand('composer --version');
console.log('Composer version output:', result.stdout.substring(0, 200));
hasComposer = result.exitCode === 0;
expect(result.exitCode).toEqual(0);
} catch (error) {
console.log('Composer CLI not available, skipping native CLI tests');
// Skip remaining tests if Composer is not installed
tap.skip.test('Composer CLI: remaining tests skipped - composer not available');
return;
hasComposer = false;
}
});
@@ -284,27 +288,32 @@ tap.test('Composer CLI: should verify server is responding', async () => {
});
tap.test('Composer CLI: should upload a package via API', async () => {
const vendorPackage = 'testvendor/test-package';
const version = '1.0.0';
await uploadComposerPackage(vendorPackage, version, composerToken, registryUrl);
await uploadComposerPackage(testPackageName, version, composerToken, registryUrl);
// Verify package exists via packages.json
const response = await fetch(`${registryUrl}/composer/packages.json`);
expect(response.status).toEqual(200);
// Verify package exists via p2 metadata endpoint (more reliable than packages.json for new packages)
const metadataResponse = await fetch(`${registryUrl}/composer/p2/${testPackageName}.json`);
expect(metadataResponse.status).toEqual(200);
const packagesJson = await response.json();
expect(packagesJson.packages).toBeDefined();
expect(packagesJson.packages[vendorPackage]).toBeDefined();
const metadata = await metadataResponse.json();
expect(metadata.packages).toBeDefined();
expect(metadata.packages[testPackageName]).toBeDefined();
expect(metadata.packages[testPackageName].length).toBeGreaterThan(0);
});
tap.test('Composer CLI: should require package from registry', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
createComposerProject(projectDir, registryUrl);
// Try to require the package we uploaded
const result = await runComposerCommand(
'require testvendor/test-package:1.0.0 --no-interaction',
`require ${testPackageName}:1.0.0 --no-interaction`,
projectDir
);
console.log('composer require output:', result.stdout);
@@ -314,8 +323,15 @@ tap.test('Composer CLI: should require package from registry', async () => {
});
tap.test('Composer CLI: should verify package in vendor directory', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
const packageDir = path.join(projectDir, 'vendor', 'testvendor', 'test-package');
// Parse vendor/package from testPackageName (e.g., "testvendor/test-pkg-abc123")
const [vendor, pkg] = testPackageName.split('/');
const packageDir = path.join(projectDir, 'vendor', vendor, pkg);
expect(fs.existsSync(packageDir)).toEqual(true);
@@ -325,25 +341,36 @@ tap.test('Composer CLI: should verify package in vendor directory', async () =>
});
tap.test('Composer CLI: should upload second version', async () => {
const vendorPackage = 'testvendor/test-package';
const version = '2.0.0';
await uploadComposerPackage(vendorPackage, version, composerToken, registryUrl);
await uploadComposerPackage(testPackageName, version, composerToken, registryUrl);
// Verify both versions exist
const response = await fetch(`${registryUrl}/composer/packages.json`);
const packagesJson = await response.json();
// Verify both versions exist via p2 metadata endpoint (Composer v2 format)
const response = await fetch(`${registryUrl}/composer/p2/${testPackageName}.json`);
expect(response.status).toEqual(200);
expect(packagesJson.packages[vendorPackage]['1.0.0']).toBeDefined();
expect(packagesJson.packages[vendorPackage]['2.0.0']).toBeDefined();
const metadata = await response.json();
expect(metadata.packages).toBeDefined();
expect(metadata.packages[testPackageName]).toBeDefined();
// Check that both versions are present
const versions = metadata.packages[testPackageName];
expect(versions.length).toBeGreaterThanOrEqual(2);
const versionNumbers = versions.map((v: any) => v.version);
expect(versionNumbers).toContain('1.0.0');
expect(versionNumbers).toContain('2.0.0');
});
tap.test('Composer CLI: should update to new version', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
// Update to version 2.0.0
const result = await runComposerCommand(
'require testvendor/test-package:2.0.0 --no-interaction',
`require ${testPackageName}:2.0.0 --no-interaction`,
projectDir
);
console.log('composer update output:', result.stdout);
@@ -355,11 +382,16 @@ tap.test('Composer CLI: should update to new version', async () => {
expect(fs.existsSync(lockPath)).toEqual(true);
const lockContent = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
const pkg = lockContent.packages.find((p: any) => p.name === 'testvendor/test-package');
const pkg = lockContent.packages.find((p: any) => p.name === testPackageName);
expect(pkg?.version).toEqual('2.0.0');
});
tap.test('Composer CLI: should search for packages', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
// Search for packages (may not work on all Composer versions)
@@ -375,23 +407,33 @@ tap.test('Composer CLI: should search for packages', async () => {
});
tap.test('Composer CLI: should show package info', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
const result = await runComposerCommand(
'show testvendor/test-package --no-interaction',
`show ${testPackageName} --no-interaction`,
projectDir
);
console.log('composer show output:', result.stdout);
expect(result.exitCode).toEqual(0);
expect(result.stdout).toContain('testvendor/test-package');
expect(result.stdout).toContain(testPackageName);
});
tap.test('Composer CLI: should remove package', async () => {
if (!hasComposer) {
console.log('Skipping - composer not available');
return;
}
const projectDir = path.join(testDir, 'consumer-project');
const result = await runComposerCommand(
'remove testvendor/test-package --no-interaction',
`remove ${testPackageName} --no-interaction`,
projectDir
);
console.log('composer remove output:', result.stdout);
@@ -399,7 +441,8 @@ tap.test('Composer CLI: should remove package', async () => {
expect(result.exitCode).toEqual(0);
// Verify package is removed from vendor
const packageDir = path.join(projectDir, 'vendor', 'testvendor', 'test-package');
const [vendor, pkg] = testPackageName.split('/');
const packageDir = path.join(projectDir, 'vendor', vendor, pkg);
expect(fs.existsSync(packageDir)).toEqual(false);
});