test: require TEST_PR_ID for write integration tests to prevent accidental mutations
Write tests no longer pick a random open PR. RUN_WRITE_TESTS=true alone is not sufficient — TEST_PR_ID must also be set, otherwise each write test is skipped with a warning. Added try/finally cleanup blocks so approval/comment/task state is always restored even on assertion failures. Updated .env.example and README to document the new requirement. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -294,6 +294,7 @@ describe('Error Handling', () => {
|
||||
});
|
||||
|
||||
const RUN_WRITES = process.env.RUN_WRITE_TESTS === 'true';
|
||||
const TEST_PR_ID = process.env.TEST_PR_ID ? parseInt(process.env.TEST_PR_ID, 10) : undefined;
|
||||
|
||||
describe('Repository / Workspace (read)', () => {
|
||||
let client: BitbucketClient;
|
||||
@@ -340,31 +341,28 @@ describe('Repository / Workspace (read)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('PR Write Operations (requires RUN_WRITE_TESTS=true)', () => {
|
||||
describe('PR Write Operations (requires RUN_WRITE_TESTS=true and TEST_PR_ID)', () => {
|
||||
let client: BitbucketClient;
|
||||
|
||||
beforeAll(() => {
|
||||
client = new BitbucketClient();
|
||||
});
|
||||
|
||||
it('should approve a PR', async () => {
|
||||
it('should approve then immediately unapprove a PR', async () => {
|
||||
if (!HAS_TOKEN || !RUN_WRITES) return;
|
||||
const prs = await client.listPullRequests(WORKSPACE, REPO_SLUG, { state: 'OPEN' });
|
||||
if (prs.length === 0) { console.log('No open PRs, skipping'); return; }
|
||||
const result = await client.approvePullRequest(WORKSPACE, REPO_SLUG, prs[0].id);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
if (!TEST_PR_ID) { console.log('⚠️ TEST_PR_ID not set, skipping approve/unapprove test'); return; }
|
||||
|
||||
it('should unapprove a PR', async () => {
|
||||
if (!HAS_TOKEN || !RUN_WRITES) return;
|
||||
const prs = await client.listPullRequests(WORKSPACE, REPO_SLUG, { state: 'OPEN' });
|
||||
if (prs.length === 0) { console.log('No open PRs, skipping'); return; }
|
||||
const result = await client.unapprovePullRequest(WORKSPACE, REPO_SLUG, prs[0].id);
|
||||
expect(result).toHaveProperty('success', true);
|
||||
await client.approvePullRequest(WORKSPACE, REPO_SLUG, TEST_PR_ID);
|
||||
try {
|
||||
const unapproved = await client.unapprovePullRequest(WORKSPACE, REPO_SLUG, TEST_PR_ID);
|
||||
expect(unapproved).toHaveProperty('success', true);
|
||||
} finally {
|
||||
await client.unapprovePullRequest(WORKSPACE, REPO_SLUG, TEST_PR_ID).catch(() => {});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Comment / Task Write Operations (requires RUN_WRITE_TESTS=true)', () => {
|
||||
describe('Comment / Task Write Operations (requires RUN_WRITE_TESTS=true and TEST_PR_ID)', () => {
|
||||
let client: BitbucketClient;
|
||||
|
||||
beforeAll(() => {
|
||||
@@ -373,35 +371,33 @@ describe('Comment / Task Write Operations (requires RUN_WRITE_TESTS=true)', () =
|
||||
|
||||
it('should add, update, then delete a comment', async () => {
|
||||
if (!HAS_TOKEN || !RUN_WRITES) return;
|
||||
const prs = await client.listPullRequests(WORKSPACE, REPO_SLUG, { state: 'OPEN' });
|
||||
if (prs.length === 0) { console.log('No open PRs, skipping'); return; }
|
||||
const prId = prs[0].id;
|
||||
if (!TEST_PR_ID) { console.log('⚠️ TEST_PR_ID not set, skipping comment test'); return; }
|
||||
|
||||
const added = await client.addPullRequestComment(WORKSPACE, REPO_SLUG, prId, { content: 'Integration test comment' });
|
||||
const added = await client.addPullRequestComment(WORKSPACE, REPO_SLUG, TEST_PR_ID, { content: 'Integration test comment' });
|
||||
expect(added).toHaveProperty('id');
|
||||
const commentId = added.id;
|
||||
|
||||
const updated = await client.updatePullRequestComment(WORKSPACE, REPO_SLUG, prId, commentId, { content: 'Updated comment' });
|
||||
expect(updated).toHaveProperty('id', commentId);
|
||||
|
||||
const deleted = await client.deletePullRequestComment(WORKSPACE, REPO_SLUG, prId, commentId);
|
||||
expect(deleted).toHaveProperty('success', true);
|
||||
try {
|
||||
const updated = await client.updatePullRequestComment(WORKSPACE, REPO_SLUG, TEST_PR_ID, commentId, { content: 'Updated comment' });
|
||||
expect(updated).toHaveProperty('id', commentId);
|
||||
} finally {
|
||||
await client.deletePullRequestComment(WORKSPACE, REPO_SLUG, TEST_PR_ID, commentId).catch(() => {});
|
||||
}
|
||||
});
|
||||
|
||||
it('should create, resolve, then delete a task', async () => {
|
||||
if (!HAS_TOKEN || !RUN_WRITES) return;
|
||||
const prs = await client.listPullRequests(WORKSPACE, REPO_SLUG, { state: 'OPEN' });
|
||||
if (prs.length === 0) { console.log('No open PRs, skipping'); return; }
|
||||
const prId = prs[0].id;
|
||||
if (!TEST_PR_ID) { console.log('⚠️ TEST_PR_ID not set, skipping task test'); return; }
|
||||
|
||||
const created = await client.createPullRequestTask(WORKSPACE, REPO_SLUG, prId, { content: 'Integration test task' });
|
||||
const created = await client.createPullRequestTask(WORKSPACE, REPO_SLUG, TEST_PR_ID, { content: 'Integration test task' });
|
||||
expect(created).toHaveProperty('id');
|
||||
const taskId = created.id;
|
||||
|
||||
const resolved = await client.updatePullRequestTask(WORKSPACE, REPO_SLUG, prId, taskId, { state: 'RESOLVED' });
|
||||
expect(resolved).toBeDefined();
|
||||
|
||||
const deleted = await client.deletePullRequestTask(WORKSPACE, REPO_SLUG, prId, taskId);
|
||||
expect(deleted).toHaveProperty('success', true);
|
||||
try {
|
||||
const resolved = await client.updatePullRequestTask(WORKSPACE, REPO_SLUG, TEST_PR_ID, taskId, { state: 'RESOLVED' });
|
||||
expect(resolved).toBeDefined();
|
||||
} finally {
|
||||
await client.deletePullRequestTask(WORKSPACE, REPO_SLUG, TEST_PR_ID, taskId).catch(() => {});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user