Files
gitea/tests/e2e/pr-review.test.ts
McMichalKandGitHub 2bcf950b78 feat(diff): Add search and extension filter to diff sidebar (#37068)
Adds a search box and a file-extension filter to the pull request diff
sidebar, so reviewers can narrow a large diff down to the files they
care about.

Both filters apply to the file tree and to the diff itself. The
extension menu follows GitHub: extensions sorted alphabetically,
dotfiles and extension-less files in their own buckets, and the
selection kept in the same `file-filters[]` query parameter, so a
filtered view is shareable and survives a reload.

The menu can list every extension in a diff, so `createTippy` gains an
opt-in `limitSizeToViewport` option that caps a popup to the space left
in the viewport and scrolls its content. Popups that do not ask for it
are unchanged.

Closes https://github.com/go-gitea/gitea/issues/27256
Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-08-23 18:31:22 +02:00

54 lines
3.0 KiB
TypeScript

import {test, expect} from '@playwright/test';
import {apiCreateFiles, apiCreatePR, apiCreateRepo, apiCreateReview, apiCreateUser, apiUserHeaders, loginUser, randomString} from './utils.ts';
test('pr review flow', async ({page, request}) => {
const poster = `rv-poster-${randomString(8)}`;
const reviewer = `rv-reviewer-${randomString(8)}`;
await Promise.all([apiCreateUser(request, poster), apiCreateUser(request, reviewer)]);
const posterHeaders = apiUserHeaders(poster);
const repoName = `e2e-prreview-${randomString(8)}`;
await apiCreateRepo(request, {name: repoName, headers: posterHeaders});
await apiCreateFiles(request, poster, repoName, [{path: 'added.txt', content: 'new content\n'}], {branch: 'main', newBranch: 'feat', headers: posterHeaders});
const prIndex = await apiCreatePR(request, poster, repoName, 'feat', 'main', 'review test', {headers: posterHeaders});
// reviewer seeds an inline comment via API so the poster's UI reply exercises the reply-to-review path (#35994)
await Promise.all([
apiCreateReview(request, poster, repoName, prIndex, {
comments: [{path: 'added.txt', body: 'inline to reply to', new_position: 1}],
headers: apiUserHeaders(reviewer),
}),
loginUser(page, poster),
]);
await page.goto(`/${poster}/${repoName}/pulls/${prIndex}/files`);
// diff viewer renders the added file with its header and one added-line row
const fileBox = page.locator('.diff-file-box[data-new-filename="added.txt"]');
await expect(fileBox.locator('.diff-file-header .file-link')).toHaveText('added.txt');
await expect(fileBox.locator('tr.add-code')).toHaveCount(1);
// commits tab badge reflects the single PR commit, and the diff stats header counts one changed file
const commitsTab = page.locator('.ui.pull.tabular.menu a.item', {has: page.locator('.octicon-git-commit')});
await expect(commitsTab.locator('.label')).toHaveText('1');
await expect(page.locator('.diff-detail-stats')).toContainText(/1 changed file/);
// poster replies to the reviewer's inline comment
const conversation = fileBox.locator('.conversation-holder');
await conversation.locator('.comment-form-reply').click();
const replyForm = conversation.locator('form');
await replyForm.locator('textarea[name="content"]').fill('my reply body');
await replyForm.getByRole('button', {name: 'Reply', exact: true}).click();
await expect(conversation.locator('.comment-body')).toContainText(['inline to reply to', 'my reply body']);
// switch to reviewer and submit an approve review
await page.context().clearCookies();
await loginUser(page, reviewer);
await page.goto(`/${poster}/${repoName}/pulls/${prIndex}/files`);
await page.locator('#review-box .js-btn-review').click();
const panel = page.locator('.review-box-panel');
await panel.locator('textarea[name="content"]').fill('LGTM');
await panel.getByRole('button', {name: 'Approve', exact: true}).click();
await expect(page.locator('.timeline-item .octicon-check').first()).toBeVisible();
await expect(page.locator('.timeline-item').filter({hasText: 'LGTM'})).toBeVisible();
});