1
0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2025-10-10 19:32:02 +00:00

refactor and add e2e js tests

This commit is contained in:
Maxim Slipenko 2025-06-07 21:27:15 +03:00
parent 922cd52f1b
commit 1d0cff2368
7 changed files with 139 additions and 67 deletions

View file

@ -82,6 +82,15 @@ type Issue struct {
PinOrder int `json:"pin_order"`
}
type IssueSuggestion struct {
Index int64 `json:"number"`
State StateType `json:"state"`
Title string `json:"title"`
IsPr bool `json:"is_pr"`
HasMerged bool `json:"merged"`
IsWorkInProgress bool `json:"draft"`
}
// CreateIssueOption options to create one issue
type CreateIssueOption struct {
// required:true

View file

@ -24,9 +24,9 @@ func IssueSuggestions(ctx *context.Context) {
isPull = optional.Some(false)
}
suggestions, err := issue_service.GetSuggestion(ctx, ctx.Repo.Repository, isPull)
suggestions, err := issue_service.GetSuggestions(ctx, ctx.Repo.Repository, isPull)
if err != nil {
ctx.ServerError("GetSuggestion", err)
ctx.ServerError("GetSuggestions", err)
return
}

View file

@ -1,47 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package issue
import (
"testing"
"forgejo.org/models/db"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest"
"forgejo.org/modules/optional"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Suggestion(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
testCases := []struct {
name string
isPull optional.Option[bool]
expectedIndexes []int64
}{
{
name: "All",
expectedIndexes: []int64{5, 1, 4, 2, 3},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
issues, err := GetSuggestion(db.DefaultContext, repo1, testCase.isPull)
require.NoError(t, err)
issueIndexes := make([]int64, 0, len(issues))
for _, issue := range issues {
issueIndexes = append(issueIndexes, issue.Index)
}
assert.Equal(t, testCase.expectedIndexes, issueIndexes)
})
}
}

View file

@ -12,7 +12,7 @@ import (
"forgejo.org/modules/structs"
)
func GetSuggestion(ctx context.Context, repo *repo_model.Repository, isPull optional.Option[bool]) ([]*structs.Issue, error) {
func GetSuggestions(ctx context.Context, repo *repo_model.Repository, isPull optional.Option[bool]) ([]*structs.IssueSuggestion, error) {
var issues issues_model.IssueList
var err error
pageSize := 1000
@ -26,20 +26,18 @@ func GetSuggestion(ctx context.Context, repo *repo_model.Repository, isPull opti
return nil, err
}
suggestions := make([]*structs.Issue, 0, len(issues))
suggestions := make([]*structs.IssueSuggestion, 0, len(issues))
for _, issue := range issues {
suggestion := &structs.Issue{
ID: issue.ID,
suggestion := &structs.IssueSuggestion{
Index: issue.Index,
Title: issue.Title,
State: issue.State(),
}
if issue.IsPull && issue.PullRequest != nil {
suggestion.PullRequest = &structs.PullRequestMeta{
HasMerged: issue.PullRequest.HasMerged,
IsWorkInProgress: issue.PullRequest.IsWorkInProgress(ctx),
}
suggestion.IsPr = true
suggestion.HasMerged = issue.PullRequest.HasMerged
suggestion.IsWorkInProgress = issue.PullRequest.IsWorkInProgress(ctx)
}
suggestions = append(suggestions, suggestion)
}

View file

@ -0,0 +1,84 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package issue
import (
"testing"
"forgejo.org/models/db"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unittest"
"forgejo.org/modules/optional"
"forgejo.org/modules/structs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_Suggestions(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
testCases := []struct {
name string
isPull optional.Option[bool]
expectedSuggestion []*structs.IssueSuggestion
}{
{
name: "All",
expectedSuggestion: []*structs.IssueSuggestion{
{
Index: 5,
State: "open",
Title: "pull5",
IsPr: true,
HasMerged: false,
IsWorkInProgress: false,
},
{
Index: 1,
State: "open",
Title: "issue1",
IsPr: false,
HasMerged: false,
IsWorkInProgress: false,
},
{
Index: 4,
State: "closed",
Title: "issue5",
IsPr: false,
HasMerged: false,
IsWorkInProgress: false,
},
{
Index: 2,
State: "open",
Title: "issue2",
IsPr: true,
HasMerged: true,
IsWorkInProgress: false,
},
{
Index: 3,
State: "open",
Title: "issue3",
IsPr: true,
HasMerged: false,
IsWorkInProgress: false,
},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
suggestion, err := GetSuggestions(db.DefaultContext, repo1, testCase.isPull)
require.NoError(t, err)
assert.Equal(t, testCase.expectedSuggestion, suggestion)
})
}
}

View file

@ -413,8 +413,14 @@ test('text expander has higher prio then prefix continuation', async ({page}) =>
await textarea.press('Enter');
await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 `);
// Test issue completion
await textarea.press('Enter');
await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 \n* `);
await textarea.pressSequentially('#pull');
await textarea.press('Enter');
await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 \n* #5 `);
await textarea.press('Enter');
await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 \n* #5 \n* `);
});
test('Combo Markdown: preview mode switch', async ({page}) => {
@ -456,3 +462,28 @@ test('Combo Markdown: preview mode switch', async ({page}) => {
await expect(previewPanel).toBeHidden();
await save_visual(page);
});
test('issue suggestions', async ({page}) => {
const response = await page.goto('/user2/repo1/issues/1');
expect(response?.status()).toBe(200);
const textarea = page.locator('#comment-form textarea[name=content]');
await textarea.focus();
await textarea.pressSequentially('#');
const suggestionList = page.locator('#comment-form .suggestions');
await expect(suggestionList).toBeVisible();
const expectedSuggestions = [
{ number: '5', label: 'pull5' },
{ number: '4', label: 'issue5' },
{ number: '3', label: 'issue3' },
{ number: '2', label: 'issue2' },
];
for (const suggestion of expectedSuggestions) {
const entry = suggestionList.locator(`li:has-text("${suggestion.number}") >> text="${suggestion.label}"`);
await expect(entry).toBeVisible();
}
})

View file

@ -2,13 +2,13 @@ import {GET} from '../modules/fetch.js';
import {parseIssueHref, parseRepoOwnerPathInfo} from '../utils.js';
export function getIssueIcon(issue) {
if (issue.pull_request) {
if (issue.is_pr) {
if (issue.state === 'open') {
if (issue.pull_request.draft === true) {
if (issue.draft === true) {
return 'octicon-git-pull-request-draft'; // WIP PR
}
return 'octicon-git-pull-request'; // Open PR
} else if (issue.pull_request.merged === true) {
} else if (issue.merged === true) {
return 'octicon-git-merge'; // Merged PR
}
return 'octicon-git-pull-request'; // Closed PR
@ -19,10 +19,10 @@ export function getIssueIcon(issue) {
}
export function getIssueColor(issue) {
if (issue.pull_request) {
if (issue.pull_request.draft === true) {
if (issue.is_pr) {
if (issue.draft === true) {
return 'grey'; // WIP PR
} else if (issue.pull_request.merged === true) {
} else if (issue.merged === true) {
return 'purple'; // Merged PR
}
}
@ -44,9 +44,6 @@ export async function fetchIssueSuggestions() {
issuePathInfo.repoName = repoOwnerPathInfo.repoName;
// then no issuePathInfo.indexString here, it is only used to exclude the current issue when "matchIssue"
}
if (!issuePathInfo.ownerName) {
throw new Error('unexpected');
}
const res = await GET(`${window.config.appSubUrl}/${issuePathInfo.ownerName}/${issuePathInfo.repoName}/issues/suggestions`);
const issues = await res.json();