diff --git a/tests/integration/pull_icon_test.go b/tests/integration/pull_icon_test.go
deleted file mode 100644
index 58dab92c3..000000000
--- a/tests/integration/pull_icon_test.go
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright 2024 The Forgejo Authors. All rights reserved.
-// SPDX-License-Identifier: AGPL-3.0-only
-
-package integration
-
-import (
- "context"
- "fmt"
- "net/http"
- "net/url"
- "strings"
- "testing"
- "time"
-
- "code.gitea.io/gitea/models/db"
- issues_model "code.gitea.io/gitea/models/issues"
- repo_model "code.gitea.io/gitea/models/repo"
- unit_model "code.gitea.io/gitea/models/unit"
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/git"
- issue_service "code.gitea.io/gitea/services/issue"
- pull_service "code.gitea.io/gitea/services/pull"
- files_service "code.gitea.io/gitea/services/repository/files"
- "code.gitea.io/gitea/tests"
-
- "github.com/PuerkitoBio/goquery"
- "github.com/stretchr/testify/assert"
-)
-
-func TestPullRequestIcons(t *testing.T) {
- onGiteaRun(t, func(t *testing.T, u *url.URL) {
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- repo, _, f := CreateDeclarativeRepo(t, user, "pr-icons", []unit_model.Type{unit_model.TypeCode, unit_model.TypePullRequests}, nil, nil)
- defer f()
-
- session := loginUser(t, user.LoginName)
-
- // Individual PRs
- t.Run("Open", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- pull := createOpenPullRequest(db.DefaultContext, t, user, repo)
- testPullRequestIcon(t, session, pull, "green", "octicon-git-pull-request")
- })
-
- t.Run("WIP (Open)", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- pull := createOpenWipPullRequest(db.DefaultContext, t, user, repo)
- testPullRequestIcon(t, session, pull, "grey", "octicon-git-pull-request-draft")
- })
-
- t.Run("Closed", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- pull := createClosedPullRequest(db.DefaultContext, t, user, repo)
- testPullRequestIcon(t, session, pull, "red", "octicon-git-pull-request-closed")
- })
-
- t.Run("WIP (Closed)", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- pull := createClosedWipPullRequest(db.DefaultContext, t, user, repo)
- testPullRequestIcon(t, session, pull, "red", "octicon-git-pull-request-closed")
- })
-
- t.Run("Merged", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- pull := createMergedPullRequest(db.DefaultContext, t, user, repo)
- testPullRequestIcon(t, session, pull, "purple", "octicon-git-merge")
- })
-
- // List
- req := NewRequest(t, "GET", repo.HTMLURL()+"/pulls?state=all")
- resp := session.MakeRequest(t, req, http.StatusOK)
- doc := NewHTMLParser(t, resp.Body)
-
- t.Run("List Open", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- testPullRequestListIcon(t, doc, "open", "green", "octicon-git-pull-request")
- })
-
- t.Run("List WIP (Open)", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- testPullRequestListIcon(t, doc, "open-wip", "grey", "octicon-git-pull-request-draft")
- })
-
- t.Run("List Closed", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- testPullRequestListIcon(t, doc, "closed", "red", "octicon-git-pull-request-closed")
- })
-
- t.Run("List Closed (WIP)", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- testPullRequestListIcon(t, doc, "closed-wip", "red", "octicon-git-pull-request-closed")
- })
-
- t.Run("List Merged", func(t *testing.T) {
- defer tests.PrintCurrentTest(t)()
-
- testPullRequestListIcon(t, doc, "merged", "purple", "octicon-git-merge")
- })
- })
-}
-
-func testPullRequestIcon(t *testing.T, session *TestSession, pr *issues_model.PullRequest, expectedColor, expectedIcon string) {
- req := NewRequest(t, "GET", pr.Issue.HTMLURL())
- resp := session.MakeRequest(t, req, http.StatusOK)
- doc := NewHTMLParser(t, resp.Body)
- doc.AssertElement(t, fmt.Sprintf("div.issue-state-label.%s > svg.%s", expectedColor, expectedIcon), true)
-
- req = NewRequest(t, "GET", pr.BaseRepo.HTMLURL()+"/branches")
- resp = session.MakeRequest(t, req, http.StatusOK)
- doc = NewHTMLParser(t, resp.Body)
- doc.AssertElement(t, fmt.Sprintf(`a[href="/%s/pulls/%d"].%s > svg.%s`, pr.BaseRepo.FullName(), pr.Issue.Index, expectedColor, expectedIcon), true)
-}
-
-func testPullRequestListIcon(t *testing.T, doc *HTMLDoc, name, expectedColor, expectedIcon string) {
- sel := doc.doc.Find("div#issue-list > div.flex-item").
- FilterFunction(func(_ int, selection *goquery.Selection) bool {
- return selection.Find(fmt.Sprintf(`div.flex-item-icon > svg.%s.%s`, expectedColor, expectedIcon)).Length() == 1 &&
- strings.HasSuffix(selection.Find("a.issue-title").Text(), name)
- })
-
- assert.Equal(t, 1, sel.Length())
-}
-
-func createOpenPullRequest(ctx context.Context, t *testing.T, user *user_model.User, repo *repo_model.Repository) *issues_model.PullRequest {
- pull := createPullRequest(t, user, repo, "open")
-
- assert.False(t, pull.Issue.IsClosed)
- assert.False(t, pull.HasMerged)
- assert.False(t, pull.IsWorkInProgress(ctx))
-
- return pull
-}
-
-func createOpenWipPullRequest(ctx context.Context, t *testing.T, user *user_model.User, repo *repo_model.Repository) *issues_model.PullRequest {
- pull := createPullRequest(t, user, repo, "open-wip")
-
- err := issue_service.ChangeTitle(ctx, pull.Issue, user, "WIP: "+pull.Issue.Title)
- assert.NoError(t, err)
-
- assert.False(t, pull.Issue.IsClosed)
- assert.False(t, pull.HasMerged)
- assert.True(t, pull.IsWorkInProgress(ctx))
-
- return pull
-}
-
-func createClosedPullRequest(ctx context.Context, t *testing.T, user *user_model.User, repo *repo_model.Repository) *issues_model.PullRequest {
- pull := createPullRequest(t, user, repo, "closed")
-
- err := issue_service.ChangeStatus(ctx, pull.Issue, user, "", true)
- assert.NoError(t, err)
-
- assert.True(t, pull.Issue.IsClosed)
- assert.False(t, pull.HasMerged)
- assert.False(t, pull.IsWorkInProgress(ctx))
-
- return pull
-}
-
-func createClosedWipPullRequest(ctx context.Context, t *testing.T, user *user_model.User, repo *repo_model.Repository) *issues_model.PullRequest {
- pull := createPullRequest(t, user, repo, "closed-wip")
-
- err := issue_service.ChangeTitle(ctx, pull.Issue, user, "WIP: "+pull.Issue.Title)
- assert.NoError(t, err)
-
- err = issue_service.ChangeStatus(ctx, pull.Issue, user, "", true)
- assert.NoError(t, err)
-
- assert.True(t, pull.Issue.IsClosed)
- assert.False(t, pull.HasMerged)
- assert.True(t, pull.IsWorkInProgress(ctx))
-
- return pull
-}
-
-func createMergedPullRequest(ctx context.Context, t *testing.T, user *user_model.User, repo *repo_model.Repository) *issues_model.PullRequest {
- pull := createPullRequest(t, user, repo, "merged")
-
- gitRepo, err := git.OpenRepository(ctx, repo.RepoPath())
- defer gitRepo.Close()
-
- assert.NoError(t, err)
-
- err = pull_service.Merge(ctx, pull, user, gitRepo, repo_model.MergeStyleMerge, pull.HeadCommitID, "merge", false)
- assert.NoError(t, err)
-
- assert.False(t, pull.Issue.IsClosed)
- assert.True(t, pull.CanAutoMerge())
- assert.False(t, pull.IsWorkInProgress(ctx))
-
- return pull
-}
-
-func createPullRequest(t *testing.T, user *user_model.User, repo *repo_model.Repository, name string) *issues_model.PullRequest {
- branch := "branch-" + name
- title := "Testing " + name
-
- _, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user, &files_service.ChangeRepoFilesOptions{
- Files: []*files_service.ChangeRepoFile{
- {
- Operation: "update",
- TreePath: "README.md",
- ContentReader: strings.NewReader("Update README"),
- },
- },
- Message: "Update README",
- OldBranch: "main",
- NewBranch: branch,
- Author: &files_service.IdentityOptions{
- Name: user.Name,
- Email: user.Email,
- },
- Committer: &files_service.IdentityOptions{
- Name: user.Name,
- Email: user.Email,
- },
- Dates: &files_service.CommitDateOptions{
- Author: time.Now(),
- Committer: time.Now(),
- },
- })
-
- assert.NoError(t, err)
-
- pullIssue := &issues_model.Issue{
- RepoID: repo.ID,
- Title: title,
- PosterID: user.ID,
- Poster: user,
- IsPull: true,
- }
-
- pullRequest := &issues_model.PullRequest{
- HeadRepoID: repo.ID,
- BaseRepoID: repo.ID,
- HeadBranch: branch,
- BaseBranch: "main",
- HeadRepo: repo,
- BaseRepo: repo,
- Type: issues_model.PullRequestGitea,
- }
- err = pull_service.NewPullRequest(git.DefaultContext, repo, pullIssue, nil, nil, pullRequest, nil)
- assert.NoError(t, err)
-
- return pullRequest
-}
diff --git a/web_src/js/components/ContextPopup.test.js b/web_src/js/components/ContextPopup.test.js
index 3884408a7..1db6c3830 100644
--- a/web_src/js/components/ContextPopup.test.js
+++ b/web_src/js/components/ContextPopup.test.js
@@ -1,166 +1,39 @@
-// Copyright 2024 The Forgejo Authors. All rights reserved.
-// SPDX-License-Identifier: AGPL-3.0-only
-
-import {flushPromises, mount} from '@vue/test-utils';
+import {mount, flushPromises} from '@vue/test-utils';
import ContextPopup from './ContextPopup.vue';
-async function assertPopup(popupData, expectedIconColor, expectedIcon) {
- const date = new Date('2024-07-13T22:00:00Z');
-
+test('renders a issue info popup', async () => {
+ const owner = 'user2';
+ const repo = 'repo1';
+ const index = 1;
vi.spyOn(global, 'fetch').mockResolvedValue({
json: vi.fn().mockResolvedValue({
ok: true,
- created_at: date.toISOString(),
- repository: {full_name: 'user2/repo1'},
- ...popupData,
- }),
- ok: true,
- });
-
- const popup = mount(ContextPopup);
- popup.vm.$el.dispatchEvent(new CustomEvent('ce-load-context-popup', {
- detail: {owner: 'user2', repo: 'repo1', index: popupData.number},
- }));
- await flushPromises();
-
- expect(popup.get('p:nth-of-type(1)').text()).toEqual(`user2/repo1 on ${date.toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'})}`);
- expect(popup.get('p:nth-of-type(2)').text()).toEqual(`${popupData.title} #${popupData.number}`);
- expect(popup.get('p:nth-of-type(3)').text()).toEqual(popupData.body);
-
- expect(popup.get('svg').classes()).toContain(expectedIcon);
- expect(popup.get('svg').classes()).toContain(expectedIconColor);
-
- for (const l of popupData.labels) {
- expect(popup.findAll('.ui.label').map((x) => x.text())).toContain(l.name);
- }
-}
-
-test('renders an open issue popup', async () => {
- await assertPopup({
- title: 'Open Issue',
- body: 'Open Issue Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'open',
- pull_request: null,
- }, 'green', 'octicon-issue-opened');
-});
-
-test('renders a closed issue popup', async () => {
- await assertPopup({
- title: 'Closed Issue',
- body: 'Closed Issue Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'closed',
- pull_request: null,
- }, 'red', 'octicon-issue-closed');
-});
-
-test('renders an open PR popup', async () => {
- await assertPopup({
- title: 'Open PR',
- body: 'Open PR Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'open',
- pull_request: {merged: false, draft: false},
- }, 'green', 'octicon-git-pull-request');
-});
-
-test('renders an open WIP PR popup', async () => {
- await assertPopup({
- title: 'WIP: Open PR',
- body: 'WIP Open PR Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'open',
- pull_request: {merged: false, draft: true},
- }, 'grey', 'octicon-git-pull-request-draft');
-});
-
-test('renders a closed PR popup', async () => {
- await assertPopup({
- title: 'Closed PR',
- body: 'Closed PR Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'closed',
- pull_request: {merged: false, draft: false},
- }, 'red', 'octicon-git-pull-request-closed');
-});
-
-test('renders a closed WIP PR popup', async () => {
- await assertPopup({
- title: 'WIP: Closed PR',
- body: 'WIP Closed PR Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'closed',
- pull_request: {merged: false, draft: true},
- }, 'red', 'octicon-git-pull-request-closed');
-});
-
-test('renders a merged PR popup', async () => {
- await assertPopup({
- title: 'Merged PR',
- body: 'Merged PR Body',
- number: 1,
- labels: [{color: 'd21b1fff', name: 'Bug'}, {color: 'aaff00', name: 'Confirmed'}],
- state: 'closed',
- pull_request: {merged: true, draft: false},
- }, 'purple', 'octicon-git-merge');
-});
-
-test('renders an issue popup with escaped HTML', async () => {
- const evil = 'evil link';
-
- vi.spyOn(global, 'fetch').mockResolvedValue({
- json: vi.fn().mockResolvedValue({
- ok: true,
- created_at: '2024-07-13T22:00:00Z',
- repository: {full_name: evil},
- title: evil,
- body: evil,
- labels: [{color: '000666', name: evil}],
- state: 'open',
+ created_at: '2023-09-30T19:00:00Z',
+ repository: {full_name: owner},
pull_request: null,
- }),
- ok: true,
- });
-
- const popup = mount(ContextPopup);
- popup.vm.$el.dispatchEvent(new CustomEvent('ce-load-context-popup', {
- detail: {owner: evil, repo: evil, index: 1},
- }));
- await flushPromises();
-
- expect(() => popup.get('.evil')).toThrowError();
- expect(popup.get('p:nth-of-type(1)').text()).toContain(evil);
- expect(popup.get('p:nth-of-type(2)').text()).toContain(evil);
- expect(popup.get('p:nth-of-type(3)').text()).toContain(evil);
-});
-
-test('renders an issue popup with emojis', async () => {
- vi.spyOn(global, 'fetch').mockResolvedValue({
- json: vi.fn().mockResolvedValue({
- ok: true,
- created_at: '2024-07-13T22:00:00Z',
- repository: {full_name: 'user2/repo1'},
- title: 'Title',
- body: 'Body',
- labels: [{color: '000666', name: 'Tag :+1:'}],
state: 'open',
- pull_request: null,
+ title: 'Normal issue',
+ body: 'Lorem ipsum...',
+ number: index,
+ labels: [{color: 'ee0701', name: "Bug :+1: "}],
}),
ok: true,
});
- const popup = mount(ContextPopup);
- popup.vm.$el.dispatchEvent(new CustomEvent('ce-load-context-popup', {
- detail: {owner: 'user2', repo: 'repo1', index: 1},
- }));
+ const wrapper = mount(ContextPopup);
+ wrapper.vm.$el.dispatchEvent(new CustomEvent('ce-load-context-popup', {detail: {owner, repo, index}}));
await flushPromises();
- expect(popup.get('.ui.label').text()).toEqual('Tag 👍');
+ // Header
+ expect(wrapper.get('p:nth-of-type(1)').text()).toEqual('user2 on Sep 30, 2023');
+ // Title
+ expect(wrapper.get('p:nth-of-type(2)').text()).toEqual('Normal issue #1');
+ // Body
+ expect(wrapper.get('p:nth-of-type(3)').text()).toEqual('Lorem ipsum...');
+ // Check that the state is correct.
+ expect(wrapper.get('svg').classes()).toContain('octicon-issue-opened');
+ // Ensure that script is not an element.
+ expect(() => wrapper.get('.evil')).toThrowError();
+ // Check content of label
+ expect(wrapper.get('.ui.label').text()).toContain("Bug 👍 ");
});