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"` 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 // CreateIssueOption options to create one issue
type CreateIssueOption struct { type CreateIssueOption struct {
// required:true // required:true

View file

@ -24,9 +24,9 @@ func IssueSuggestions(ctx *context.Context) {
isPull = optional.Some(false) 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 { if err != nil {
ctx.ServerError("GetSuggestion", err) ctx.ServerError("GetSuggestions", err)
return 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" "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 issues issues_model.IssueList
var err error var err error
pageSize := 1000 pageSize := 1000
@ -26,20 +26,18 @@ func GetSuggestion(ctx context.Context, repo *repo_model.Repository, isPull opti
return nil, err return nil, err
} }
suggestions := make([]*structs.Issue, 0, len(issues)) suggestions := make([]*structs.IssueSuggestion, 0, len(issues))
for _, issue := range issues { for _, issue := range issues {
suggestion := &structs.Issue{ suggestion := &structs.IssueSuggestion{
ID: issue.ID,
Index: issue.Index, Index: issue.Index,
Title: issue.Title, Title: issue.Title,
State: issue.State(), State: issue.State(),
} }
if issue.IsPull && issue.PullRequest != nil { if issue.IsPull && issue.PullRequest != nil {
suggestion.PullRequest = &structs.PullRequestMeta{ suggestion.IsPr = true
HasMerged: issue.PullRequest.HasMerged, suggestion.HasMerged = issue.PullRequest.HasMerged
IsWorkInProgress: issue.PullRequest.IsWorkInProgress(ctx), suggestion.IsWorkInProgress = issue.PullRequest.IsWorkInProgress(ctx)
}
} }
suggestions = append(suggestions, suggestion) 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 textarea.press('Enter');
await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 `); await expect(textarea).toHaveValue(`* first\n* 😸\n* @user2 `);
// Test issue completion
await textarea.press('Enter'); 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}) => { 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 expect(previewPanel).toBeHidden();
await save_visual(page); 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'; import {parseIssueHref, parseRepoOwnerPathInfo} from '../utils.js';
export function getIssueIcon(issue) { export function getIssueIcon(issue) {
if (issue.pull_request) { if (issue.is_pr) {
if (issue.state === 'open') { 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-draft'; // WIP PR
} }
return 'octicon-git-pull-request'; // Open 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-merge'; // Merged PR
} }
return 'octicon-git-pull-request'; // Closed PR return 'octicon-git-pull-request'; // Closed PR
@ -19,10 +19,10 @@ export function getIssueIcon(issue) {
} }
export function getIssueColor(issue) { export function getIssueColor(issue) {
if (issue.pull_request) { if (issue.is_pr) {
if (issue.pull_request.draft === true) { if (issue.draft === true) {
return 'grey'; // WIP PR return 'grey'; // WIP PR
} else if (issue.pull_request.merged === true) { } else if (issue.merged === true) {
return 'purple'; // Merged PR return 'purple'; // Merged PR
} }
} }
@ -44,9 +44,6 @@ export async function fetchIssueSuggestions() {
issuePathInfo.repoName = repoOwnerPathInfo.repoName; issuePathInfo.repoName = repoOwnerPathInfo.repoName;
// then no issuePathInfo.indexString here, it is only used to exclude the current issue when "matchIssue" // 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 res = await GET(`${window.config.appSubUrl}/${issuePathInfo.ownerName}/${issuePathInfo.repoName}/issues/suggestions`);
const issues = await res.json(); const issues = await res.json();