2017-04-25 03:24:51 -04:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2017-04-25 03:24:51 -04:00
2022-09-02 15:18:23 -04:00
package integration
2017-04-25 03:24:51 -04:00
import (
2017-07-15 10:21:51 -04:00
"fmt"
2017-04-25 03:24:51 -04:00
"net/http"
2020-02-01 14:11:32 -05:00
"path"
2018-05-01 03:04:36 -04:00
"strings"
2017-04-25 03:24:51 -04:00
"testing"
2020-02-01 14:11:32 -05:00
"time"
2017-07-15 10:21:51 -04:00
2023-12-31 11:54:43 -05:00
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
2024-02-19 08:32:37 -05:00
"code.gitea.io/gitea/modules/git"
2017-07-15 10:21:51 -04:00
"code.gitea.io/gitea/modules/setting"
2024-01-07 05:20:22 -05:00
"code.gitea.io/gitea/modules/test"
2024-02-19 08:32:37 -05:00
"code.gitea.io/gitea/modules/translation"
2023-12-31 11:54:43 -05:00
repo_service "code.gitea.io/gitea/services/repository"
2022-09-02 15:18:23 -04:00
"code.gitea.io/gitea/tests"
2017-07-15 10:21:51 -04:00
2018-05-01 03:04:36 -04:00
"github.com/PuerkitoBio/goquery"
2017-07-15 10:21:51 -04:00
"github.com/stretchr/testify/assert"
2024-02-19 08:32:37 -05:00
"github.com/stretchr/testify/require"
2017-04-25 03:24:51 -04:00
)
func TestViewRepo ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2017-04-25 03:24:51 -04:00
2022-10-13 04:31:10 -04:00
session := loginUser ( t , "user2" )
2017-06-09 20:41:36 -04:00
req := NewRequest ( t , "GET" , "/user2/repo1" )
2022-10-13 04:31:10 -04:00
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
noDescription := htmlDoc . doc . Find ( "#repo-desc" ) . Children ( )
repoTopics := htmlDoc . doc . Find ( "#repo-topics" ) . Children ( )
repoSummary := htmlDoc . doc . Find ( ".repository-summary" ) . Children ( )
assert . True ( t , noDescription . HasClass ( "no-description" ) )
assert . True ( t , repoTopics . HasClass ( "repo-topic" ) )
assert . True ( t , repoSummary . HasClass ( "repository-menu" ) )
2017-06-14 22:50:12 -04:00
2023-09-13 22:59:53 -04:00
req = NewRequest ( t , "GET" , "/org3/repo3" )
2017-07-07 15:36:47 -04:00
MakeRequest ( t , req , http . StatusNotFound )
2017-06-14 22:50:12 -04:00
2022-10-13 04:31:10 -04:00
session = loginUser ( t , "user1" )
2017-07-07 15:36:47 -04:00
session . MakeRequest ( t , req , http . StatusNotFound )
2017-06-14 22:50:12 -04:00
}
2023-12-31 10:24:05 -05:00
func TestViewRepoCloneMethods ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
getCloneMethods := func ( ) [ ] string {
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
cloneMoreMethodsHTML := htmlDoc . doc . Find ( "#more-btn div a" )
var methods [ ] string
cloneMoreMethodsHTML . Each ( func ( i int , s * goquery . Selection ) {
a , _ := s . Attr ( "href" )
methods = append ( methods , a )
} )
return methods
}
testCloneMethods := func ( expected [ ] string ) {
methods := getCloneMethods ( )
assert . Len ( t , methods , len ( expected ) )
for i , expectedMethod := range expected {
assert . Contains ( t , methods [ i ] , expectedMethod )
}
}
t . Run ( "Defaults" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
testCloneMethods ( [ ] string { "/master.zip" , "/master.tar.gz" , "/master.bundle" , "vscode://" } )
} )
t . Run ( "Customized methods" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
defer test . MockVariableValue ( & setting . Repository . DownloadOrCloneMethods , [ ] string { "vscodium-clone" , "download-targz" } ) ( )
testCloneMethods ( [ ] string { "vscodium://" , "/master.tar.gz" } )
} )
t . Run ( "Individual methods" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
singleMethodTest := func ( method , expectedURLPart string ) {
t . Run ( method , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
defer test . MockVariableValue ( & setting . Repository . DownloadOrCloneMethods , [ ] string { method } ) ( )
testCloneMethods ( [ ] string { expectedURLPart } )
} )
}
cases := map [ string ] string {
"download-zip" : "/master.zip" ,
"download-targz" : "/master.tar.gz" ,
"download-bundle" : "/master.bundle" ,
"vscode-clone" : "vscode://" ,
"vscodium-clone" : "vscodium://" ,
}
for method , expectedURLPart := range cases {
singleMethodTest ( method , expectedURLPart )
}
} )
t . Run ( "All methods" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
defer test . MockVariableValue ( & setting . Repository . DownloadOrCloneMethods , setting . RecognisedRepositoryDownloadOrCloneMethods ) ( )
methods := getCloneMethods ( )
// We compare against
// len(setting.RecognisedRepositoryDownloadOrCloneMethods) - 1, because
// the test environment does not currently set things up for the cite
// method to display.
assert . GreaterOrEqual ( t , len ( methods ) , len ( setting . RecognisedRepositoryDownloadOrCloneMethods ) - 1 )
} )
}
2020-02-01 14:11:32 -05:00
func testViewRepo ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2017-06-14 22:50:12 -04:00
2023-09-13 22:59:53 -04:00
req := NewRequest ( t , "GET" , "/org3/repo3" )
2017-06-17 00:49:45 -04:00
session := loginUser ( t , "user2" )
2020-02-01 14:11:32 -05:00
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
files := htmlDoc . doc . Find ( "#repo-files-table > TBODY > TR" )
type file struct {
fileName string
commitID string
commitMsg string
commitTime string
}
var items [ ] file
files . Each ( func ( i int , s * goquery . Selection ) {
tds := s . Find ( "td" )
var f file
tds . Each ( func ( i int , s * goquery . Selection ) {
if i == 0 {
f . fileName = strings . TrimSpace ( s . Text ( ) )
} else if i == 1 {
a := s . Find ( "a" )
f . commitMsg = strings . TrimSpace ( a . Text ( ) )
l , _ := a . Attr ( "href" )
f . commitID = path . Base ( l )
}
} )
2023-04-10 19:01:20 -04:00
// convert "2017-06-14 21:54:21 +0800" to "Wed, 14 Jun 2017 13:54:21 UTC"
htmlTimeString , _ := s . Find ( "relative-time.time-since" ) . Attr ( "datetime" )
htmlTime , _ := time . Parse ( time . RFC3339 , htmlTimeString )
In TestViewRepo2, convert computed timezones to local time (#24579)
This fixes up https://github.com/go-gitea/gitea/pull/10446; in that, the
*expected* timezone was changed to the local timezone, but the computed
timezone was left in UTC.
The result was this failure, when run on a non-UTC system:
```
Diff:
--- Expected
+++ Actual
@@ -5,3 +5,3 @@
commitMsg: (string) (len=12) "init project",
- commitTime: (string) (len=29) "Wed, 14 Jun 2017 09:54:21 EDT"
+ commitTime: (string) (len=29) "Wed, 14 Jun 2017 13:54:21 UTC"
},
@@ -11,3 +11,3 @@
commitMsg: (string) (len=12) "init project",
- commitTime: (string) (len=29) "Wed, 14 Jun 2017 09:54:21 EDT"
+ commitTime: (string) (len=29) "Wed, 14 Jun 2017 13:54:21 UTC"
}
Test: TestViewRepo2
```
I assume this was probably missed since the CI servers all run in UTC?
The Format() string "Mon, 02 Jan 2006 15:04:05 UTC" was incorrect: 'UTC'
isn't recognized as a variable placeholder, but was just being copied
verbatim. It should use 'MST' in order to command Format() to output the
attached timezone, which is what `time.RFC1123` has.
2023-05-08 09:07:41 -04:00
f . commitTime = htmlTime . In ( time . Local ) . Format ( time . RFC1123 )
2020-02-01 14:11:32 -05:00
items = append ( items , f )
} )
2020-02-24 22:05:00 -05:00
commitT := time . Date ( 2017 , time . June , 14 , 13 , 54 , 21 , 0 , time . UTC ) . In ( time . Local ) . Format ( time . RFC1123 )
2020-02-01 14:11:32 -05:00
assert . EqualValues ( t , [ ] file {
{
fileName : "doc" ,
commitID : "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6" ,
commitMsg : "init project" ,
2020-02-24 22:05:00 -05:00
commitTime : commitT ,
2020-02-01 14:11:32 -05:00
} ,
{
fileName : "README.md" ,
commitID : "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6" ,
commitMsg : "init project" ,
2020-02-24 22:05:00 -05:00
commitTime : commitT ,
2020-02-01 14:11:32 -05:00
} ,
} , items )
}
func TestViewRepo2 ( t * testing . T ) {
// no last commit cache
testViewRepo ( t )
// enable last commit cache for all repositories
oldCommitsCount := setting . CacheService . LastCommit . CommitsCount
setting . CacheService . LastCommit . CommitsCount = 0
// first view will not hit the cache
testViewRepo ( t )
// second view will hit the cache
testViewRepo ( t )
setting . CacheService . LastCommit . CommitsCount = oldCommitsCount
2017-06-14 22:50:12 -04:00
}
func TestViewRepo3 ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2017-06-14 22:50:12 -04:00
2023-09-13 22:59:53 -04:00
req := NewRequest ( t , "GET" , "/org3/repo3" )
2017-07-16 22:04:43 -04:00
session := loginUser ( t , "user4" )
2017-07-07 15:36:47 -04:00
session . MakeRequest ( t , req , http . StatusOK )
2017-04-25 03:24:51 -04:00
}
2017-07-15 10:21:51 -04:00
func TestViewRepo1CloneLinkAnonymous ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2017-07-15 10:21:51 -04:00
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
link , exists := htmlDoc . doc . Find ( "#repo-clone-https" ) . Attr ( "data-link" )
assert . True ( t , exists , "The template has changed" )
assert . Equal ( t , setting . AppURL + "user2/repo1.git" , link )
_ , exists = htmlDoc . doc . Find ( "#repo-clone-ssh" ) . Attr ( "data-link" )
assert . False ( t , exists )
}
func TestViewRepo1CloneLinkAuthorized ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2017-07-15 10:21:51 -04:00
session := loginUser ( t , "user2" )
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
link , exists := htmlDoc . doc . Find ( "#repo-clone-https" ) . Attr ( "data-link" )
assert . True ( t , exists , "The template has changed" )
assert . Equal ( t , setting . AppURL + "user2/repo1.git" , link )
link , exists = htmlDoc . doc . Find ( "#repo-clone-ssh" ) . Attr ( "data-link" )
assert . True ( t , exists , "The template has changed" )
2022-02-07 16:56:45 -05:00
sshURL := fmt . Sprintf ( "ssh://%s@%s:%d/user2/repo1.git" , setting . SSH . User , setting . SSH . Domain , setting . SSH . Port )
2017-07-15 10:21:51 -04:00
assert . Equal ( t , sshURL , link )
}
2018-05-01 03:04:36 -04:00
func TestViewRepoWithSymlinks ( t * testing . T ) {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2018-05-01 03:04:36 -04:00
session := loginUser ( t , "user2" )
req := NewRequest ( t , "GET" , "/user2/repo20.git" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
2020-08-26 11:52:44 -04:00
files := htmlDoc . doc . Find ( "#repo-files-table > TBODY > TR > TD.name > SPAN.truncate" )
2018-05-01 03:04:36 -04:00
items := files . Map ( func ( i int , s * goquery . Selection ) string {
2020-02-11 12:02:41 -05:00
cls , _ := s . Find ( "SVG" ) . Attr ( "class" )
2018-05-01 03:04:36 -04:00
file := strings . Trim ( s . Find ( "A" ) . Text ( ) , " \t\n" )
return fmt . Sprintf ( "%s: %s" , file , cls )
} )
2021-06-07 01:27:09 -04:00
assert . Len ( t , items , 5 )
2022-03-31 20:15:46 -04:00
assert . Equal ( t , "a: svg octicon-file-directory-fill" , items [ 0 ] )
2023-06-22 18:05:52 -04:00
assert . Equal ( t , "link_b: svg octicon-file-directory-symlink" , items [ 1 ] )
2021-06-07 01:27:09 -04:00
assert . Equal ( t , "link_d: svg octicon-file-symlink-file" , items [ 2 ] )
assert . Equal ( t , "link_hi: svg octicon-file-symlink-file" , items [ 3 ] )
assert . Equal ( t , "link_link: svg octicon-file-symlink-file" , items [ 4 ] )
2018-05-01 03:04:36 -04:00
}
2019-01-27 16:13:15 -05:00
// TestViewAsRepoAdmin tests PR #2167
func TestViewAsRepoAdmin ( t * testing . T ) {
for user , expectedNoDescription := range map [ string ] bool {
"user2" : true ,
2019-02-19 02:19:28 -05:00
"user4" : false ,
2019-01-27 16:13:15 -05:00
} {
2022-09-02 15:18:23 -04:00
defer tests . PrepareTestEnv ( t ) ( )
2019-01-27 16:13:15 -05:00
session := loginUser ( t , user )
req := NewRequest ( t , "GET" , "/user2/repo1.git" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
noDescription := htmlDoc . doc . Find ( "#repo-desc" ) . Children ( )
2022-10-13 04:31:10 -04:00
repoTopics := htmlDoc . doc . Find ( "#repo-topics" ) . Children ( )
repoSummary := htmlDoc . doc . Find ( ".repository-summary" ) . Children ( )
2019-01-27 16:13:15 -05:00
assert . Equal ( t , expectedNoDescription , noDescription . HasClass ( "no-description" ) )
2022-10-13 04:31:10 -04:00
assert . True ( t , repoTopics . HasClass ( "repo-topic" ) )
assert . True ( t , repoSummary . HasClass ( "repository-menu" ) )
2019-01-27 16:13:15 -05:00
}
}
2022-10-13 04:31:10 -04:00
2023-08-18 05:21:24 -04:00
func TestRepoHTMLTitle ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
t . Run ( "Repository homepage" , func ( t * testing . T ) {
t . Run ( "Without description" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo1" )
assert . EqualValues ( t , "user2/repo1 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "With description" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user27/repo49" )
assert . EqualValues ( t , "user27/repo49: A wonderful repository with more than just a README.md - Gitea: Git with a cup of tea" , htmlTitle )
} )
} )
t . Run ( "Code view" , func ( t * testing . T ) {
t . Run ( "Directory" , func ( t * testing . T ) {
t . Run ( "Default branch" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/branch/master/deep/nesting" )
assert . EqualValues ( t , "repo59/deep/nesting at master - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Non-default branch" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/branch/cake-recipe/deep/nesting" )
assert . EqualValues ( t , "repo59/deep/nesting at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Commit" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/" )
assert . EqualValues ( t , "repo59/deep/nesting at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Tag" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/tag/v1.0/deep/nesting/" )
assert . EqualValues ( t , "repo59/deep/nesting at v1.0 - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
} )
t . Run ( "File" , func ( t * testing . T ) {
t . Run ( "Default branch" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/branch/master/deep/nesting/folder/secret_sauce_recipe.txt" )
assert . EqualValues ( t , "repo59/deep/nesting/folder/secret_sauce_recipe.txt at master - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Non-default branch" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/branch/cake-recipe/deep/nesting/folder/secret_sauce_recipe.txt" )
assert . EqualValues ( t , "repo59/deep/nesting/folder/secret_sauce_recipe.txt at cake-recipe - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Commit" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/commit/d8f53dfb33f6ccf4169c34970b5e747511c18beb/deep/nesting/folder/secret_sauce_recipe.txt" )
assert . EqualValues ( t , "repo59/deep/nesting/folder/secret_sauce_recipe.txt at d8f53dfb33f6ccf4169c34970b5e747511c18beb - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "Tag" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo59/src/tag/v1.0/deep/nesting/folder/secret_sauce_recipe.txt" )
assert . EqualValues ( t , "repo59/deep/nesting/folder/secret_sauce_recipe.txt at v1.0 - user2/repo59 - Gitea: Git with a cup of tea" , htmlTitle )
} )
} )
} )
t . Run ( "Issues view" , func ( t * testing . T ) {
t . Run ( "Overview page" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo1/issues" )
assert . EqualValues ( t , "Issues - user2/repo1 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "View issue page" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo1/issues/1" )
assert . EqualValues ( t , "#1 - issue1 - user2/repo1 - Gitea: Git with a cup of tea" , htmlTitle )
} )
} )
t . Run ( "Pull requests view" , func ( t * testing . T ) {
t . Run ( "Overview page" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo1/pulls" )
assert . EqualValues ( t , "Pull Requests - user2/repo1 - Gitea: Git with a cup of tea" , htmlTitle )
} )
t . Run ( "View pull request" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
htmlTitle := GetHTMLTitle ( t , nil , "/user2/repo1/pulls/2" )
assert . EqualValues ( t , "#2 - issue2 - user2/repo1 - Gitea: Git with a cup of tea" , htmlTitle )
} )
} )
}
2022-10-13 04:31:10 -04:00
// TestViewFileInRepo repo description, topics and summary should not be displayed when viewing a file
func TestViewFileInRepo ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
req := NewRequest ( t , "GET" , "/user2/repo1/src/branch/master/README.md" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
description := htmlDoc . doc . Find ( "#repo-desc" )
repoTopics := htmlDoc . doc . Find ( "#repo-topics" )
repoSummary := htmlDoc . doc . Find ( ".repository-summary" )
assert . EqualValues ( t , 0 , description . Length ( ) )
assert . EqualValues ( t , 0 , repoTopics . Length ( ) )
assert . EqualValues ( t , 0 , repoSummary . Length ( ) )
}
2024-01-06 04:06:17 -05:00
func TestViewFileInRepoRSSFeed ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
hasFileRSSFeed := func ( t * testing . T , ref string ) bool {
t . Helper ( )
req := NewRequestf ( t , "GET" , "/user2/repo1/src/%s/README.md" , ref )
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
fileFeed := htmlDoc . doc . Find ( ` a[href*="/user2/repo1/rss/"] ` )
return fileFeed . Length ( ) != 0
}
t . Run ( "branch" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
assert . True ( t , hasFileRSSFeed ( t , "branch/master" ) )
} )
t . Run ( "tag" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
assert . False ( t , hasFileRSSFeed ( t , "tag/v1.1" ) )
} )
t . Run ( "commit" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
assert . False ( t , hasFileRSSFeed ( t , "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d" ) )
} )
}
2022-10-13 04:31:10 -04:00
// TestBlameFileInRepo repo description, topics and summary should not be displayed when running blame on a file
func TestBlameFileInRepo ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
2024-02-19 08:32:37 -05:00
t . Run ( "Assert" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
2022-10-13 04:31:10 -04:00
2024-02-19 08:32:37 -05:00
req := NewRequest ( t , "GET" , "/user2/repo1/blame/branch/master/README.md" )
resp := session . MakeRequest ( t , req , http . StatusOK )
2022-10-13 04:31:10 -04:00
2024-02-19 08:32:37 -05:00
htmlDoc := NewHTMLParser ( t , resp . Body )
description := htmlDoc . doc . Find ( "#repo-desc" )
repoTopics := htmlDoc . doc . Find ( "#repo-topics" )
repoSummary := htmlDoc . doc . Find ( ".repository-summary" )
assert . EqualValues ( t , 0 , description . Length ( ) )
assert . EqualValues ( t , 0 , repoTopics . Length ( ) )
assert . EqualValues ( t , 0 , repoSummary . Length ( ) )
} )
t . Run ( "File size" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } )
gitRepo , err := git . OpenRepository ( git . DefaultContext , repo . RepoPath ( ) )
require . NoError ( t , err )
defer gitRepo . Close ( )
commit , err := gitRepo . GetCommit ( "HEAD" )
require . NoError ( t , err )
blob , err := commit . GetBlobByPath ( "README.md" )
require . NoError ( t , err )
fileSize := blob . Size ( )
require . NotZero ( t , fileSize )
t . Run ( "Above maximum" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
defer test . MockVariableValue ( & setting . UI . MaxDisplayFileSize , fileSize ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/blame/branch/master/README.md" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
assert . Contains ( t , htmlDoc . Find ( ".code-view" ) . Text ( ) , translation . NewLocale ( "en-US" ) . Tr ( "repo.file_too_large" ) )
} )
t . Run ( "Under maximum" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
defer test . MockVariableValue ( & setting . UI . MaxDisplayFileSize , fileSize + 1 ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/blame/branch/master/README.md" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
assert . NotContains ( t , htmlDoc . Find ( ".code-view" ) . Text ( ) , translation . NewLocale ( "en-US" ) . Tr ( "repo.file_too_large" ) )
} )
} )
2022-10-13 04:31:10 -04:00
}
// TestViewRepoDirectory repo description, topics and summary should not be displayed when within a directory
func TestViewRepoDirectory ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
req := NewRequest ( t , "GET" , "/user2/repo20/src/branch/master/a" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
description := htmlDoc . doc . Find ( "#repo-desc" )
repoTopics := htmlDoc . doc . Find ( "#repo-topics" )
repoSummary := htmlDoc . doc . Find ( ".repository-summary" )
repoFilesTable := htmlDoc . doc . Find ( "#repo-files-table" )
assert . NotZero ( t , len ( repoFilesTable . Nodes ) )
assert . Zero ( t , description . Length ( ) )
assert . Zero ( t , repoTopics . Length ( ) )
assert . Zero ( t , repoSummary . Length ( ) )
}
2023-03-03 05:01:33 -05:00
2023-03-08 20:24:23 -05:00
// ensure that the all the different ways to find and render a README work
func TestViewRepoDirectoryReadme ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
// there are many combinations:
// - READMEs can be .md, .txt, or have no extension
// - READMEs can be tagged with a language and even a country code
// - READMEs can be stored in docs/, .gitea/, or .github/
// - READMEs can be symlinks to other files
// - READMEs can be broken symlinks which should not render
//
// this doesn't cover all possible cases, just the major branches of the code
session := loginUser ( t , "user2" )
check := func ( name , url , expectedFilename , expectedReadmeType , expectedContent string ) {
t . Run ( name , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , url )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
readmeName := htmlDoc . doc . Find ( "h4.file-header" )
readmeContent := htmlDoc . doc . Find ( ".file-view" ) // TODO: add a id="readme" to the output to make this test more precise
readmeType , _ := readmeContent . Attr ( "class" )
assert . Equal ( t , expectedFilename , strings . TrimSpace ( readmeName . Text ( ) ) )
assert . Contains ( t , readmeType , expectedReadmeType )
assert . Contains ( t , readmeContent . Text ( ) , expectedContent )
} )
}
// viewing the top level
check ( "Home" , "/user2/readme-test/" , "README.md" , "markdown" , "The cake is a lie." )
// viewing different file extensions
check ( "md" , "/user2/readme-test/src/branch/master/" , "README.md" , "markdown" , "The cake is a lie." )
check ( "txt" , "/user2/readme-test/src/branch/txt/" , "README.txt" , "plain-text" , "My spoon is too big." )
check ( "plain" , "/user2/readme-test/src/branch/plain/" , "README" , "plain-text" , "Birken my stocks gee howdy" )
check ( "i18n" , "/user2/readme-test/src/branch/i18n/" , "README.zh.md" , "markdown" , "蛋糕是一个谎言" )
2023-10-03 03:37:06 -04:00
// using HEAD ref
check ( "branch-HEAD" , "/user2/readme-test/src/branch/HEAD/" , "README.md" , "markdown" , "The cake is a lie." )
check ( "commit-HEAD" , "/user2/readme-test/src/commit/HEAD/" , "README.md" , "markdown" , "The cake is a lie." )
2023-03-08 20:24:23 -05:00
// viewing different subdirectories
check ( "subdir" , "/user2/readme-test/src/branch/subdir/libcake" , "README.md" , "markdown" , "Four pints of sugar." )
check ( "docs-direct" , "/user2/readme-test/src/branch/special-subdir-docs/docs/" , "README.md" , "markdown" , "This is in docs/" )
check ( "docs" , "/user2/readme-test/src/branch/special-subdir-docs/" , "docs/README.md" , "markdown" , "This is in docs/" )
check ( ".gitea" , "/user2/readme-test/src/branch/special-subdir-.gitea/" , ".gitea/README.md" , "markdown" , "This is in .gitea/" )
check ( ".github" , "/user2/readme-test/src/branch/special-subdir-.github/" , ".github/README.md" , "markdown" , "This is in .github/" )
// symlinks
// symlinks are subtle:
// - they should be able to handle going a reasonable number of times up and down in the tree
// - they shouldn't get stuck on link cycles
// - they should determine the filetype based on the name of the link, not the target
check ( "symlink" , "/user2/readme-test/src/branch/symlink/" , "README.md" , "markdown" , "This is in some/other/path" )
check ( "symlink-multiple" , "/user2/readme-test/src/branch/symlink/some/" , "README.txt" , "plain-text" , "This is in some/other/path" )
check ( "symlink-up-and-down" , "/user2/readme-test/src/branch/symlink/up/back/down/down" , "README.md" , "markdown" , "It's a me, mario" )
// testing fallback rules
// READMEs are searched in this order:
// - [README.zh-cn.md, README.zh_cn.md, README.zh.md, README_zh.md, README.md, README.txt, README,
// docs/README.zh-cn.md, docs/README.zh_cn.md, docs/README.zh.md, docs/README_zh.md, docs/README.md, docs/README.txt, docs/README,
// .gitea/README.zh-cn.md, .gitea/README.zh_cn.md, .gitea/README.zh.md, .gitea/README_zh.md, .gitea/README.md, .gitea/README.txt, .gitea/README,
// .github/README.zh-cn.md, .github/README.zh_cn.md, .github/README.zh.md, .github/README_zh.md, .github/README.md, .github/README.txt, .github/README]
// and a broken/looped symlink counts as not existing at all and should be skipped.
// again, this doesn't cover all cases, but it covers a few
check ( "fallback/top" , "/user2/readme-test/src/branch/fallbacks/" , "README.en.md" , "markdown" , "This is README.en.md" )
check ( "fallback/2" , "/user2/readme-test/src/branch/fallbacks2/" , "README.md" , "markdown" , "This is README.md" )
check ( "fallback/3" , "/user2/readme-test/src/branch/fallbacks3/" , "README" , "plain-text" , "This is README" )
check ( "fallback/4" , "/user2/readme-test/src/branch/fallbacks4/" , "docs/README.en.md" , "markdown" , "This is docs/README.en.md" )
check ( "fallback/5" , "/user2/readme-test/src/branch/fallbacks5/" , "docs/README.md" , "markdown" , "This is docs/README.md" )
check ( "fallback/6" , "/user2/readme-test/src/branch/fallbacks6/" , "docs/README" , "plain-text" , "This is docs/README" )
check ( "fallback/7" , "/user2/readme-test/src/branch/fallbacks7/" , ".gitea/README.en.md" , "markdown" , "This is .gitea/README.en.md" )
check ( "fallback/8" , "/user2/readme-test/src/branch/fallbacks8/" , ".gitea/README.md" , "markdown" , "This is .gitea/README.md" )
check ( "fallback/9" , "/user2/readme-test/src/branch/fallbacks9/" , ".gitea/README" , "plain-text" , "This is .gitea/README" )
// this case tests that broken symlinks count as missing files, instead of rendering their contents
check ( "fallbacks-broken-symlinks" , "/user2/readme-test/src/branch/fallbacks-broken-symlinks/" , "docs/README" , "plain-text" , "This is docs/README" )
// some cases that should NOT render a README
// - /readme
// - /.github/docs/README.md
// - a symlink loop
missing := func ( name , url string ) {
t . Run ( "missing/" + name , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , url )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
_ , exists := htmlDoc . doc . Find ( ".file-view" ) . Attr ( "class" )
assert . False ( t , exists , "README should not have rendered" )
} )
}
missing ( "sp-ace" , "/user2/readme-test/src/branch/sp-ace/" )
missing ( "nested-special" , "/user2/readme-test/src/branch/special-subdir-nested/subproject" ) // the special subdirs should only trigger on the repo root
2023-04-10 23:00:19 -04:00
missing ( "special-subdir-nested" , "/user2/readme-test/src/branch/special-subdir-nested/" )
2023-03-08 20:24:23 -05:00
missing ( "symlink-loop" , "/user2/readme-test/src/branch/symlink-loop/" )
}
2023-09-14 15:53:57 -04:00
func TestRenamedFileHistory ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
t . Run ( "Renamed file" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo59/commits/branch/master/license" )
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
renameNotice := htmlDoc . doc . Find ( ".ui.bottom.attached.header" )
assert . Equal ( t , 1 , renameNotice . Length ( ) )
assert . Contains ( t , renameNotice . Text ( ) , "Renamed from licnse (Browse further)" )
oldFileHistoryLink , ok := renameNotice . Find ( "a" ) . Attr ( "href" )
assert . True ( t , ok )
assert . Equal ( t , "/user2/repo59/commits/commit/80b83c5c8220c3aa3906e081f202a2a7563ec879/licnse" , oldFileHistoryLink )
} )
t . Run ( "Non renamed file" , func ( t * testing . T ) {
req := NewRequest ( t , "GET" , "/user2/repo59/commits/branch/master/README.md" )
resp := MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
htmlDoc . AssertElement ( t , ".ui.bottom.attached.header" , false )
} )
}
2023-03-15 17:51:39 -04:00
func TestMarkDownReadmeImage ( t * testing . T ) {
2023-03-03 05:01:33 -05:00
defer tests . PrepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
req := NewRequest ( t , "GET" , "/user2/repo1/src/branch/home-md-img-check" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
2023-03-15 17:51:39 -04:00
src , exists := htmlDoc . doc . Find ( ` .markdown img ` ) . Attr ( "src" )
assert . True ( t , exists , "Image not found in README" )
2023-04-22 17:56:27 -04:00
assert . Equal ( t , "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg" , src )
2023-03-03 05:01:33 -05:00
req = NewRequest ( t , "GET" , "/user2/repo1/src/branch/home-md-img-check/README.md" )
resp = session . MakeRequest ( t , req , http . StatusOK )
htmlDoc = NewHTMLParser ( t , resp . Body )
2023-03-15 17:51:39 -04:00
src , exists = htmlDoc . doc . Find ( ` .markdown img ` ) . Attr ( "src" )
assert . True ( t , exists , "Image not found in markdown file" )
2023-04-22 17:56:27 -04:00
assert . Equal ( t , "/user2/repo1/media/branch/home-md-img-check/test-fake-img.jpg" , src )
2023-03-15 17:51:39 -04:00
}
func TestMarkDownReadmeImageSubfolder ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
session := loginUser ( t , "user2" )
// this branch has the README in the special docs/README.md location
req := NewRequest ( t , "GET" , "/user2/repo1/src/branch/sub-home-md-img-check" )
resp := session . MakeRequest ( t , req , http . StatusOK )
htmlDoc := NewHTMLParser ( t , resp . Body )
src , exists := htmlDoc . doc . Find ( ` .markdown img ` ) . Attr ( "src" )
assert . True ( t , exists , "Image not found in README" )
2023-04-22 17:56:27 -04:00
assert . Equal ( t , "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg" , src )
2023-03-15 17:51:39 -04:00
req = NewRequest ( t , "GET" , "/user2/repo1/src/branch/sub-home-md-img-check/docs/README.md" )
resp = session . MakeRequest ( t , req , http . StatusOK )
htmlDoc = NewHTMLParser ( t , resp . Body )
src , exists = htmlDoc . doc . Find ( ` .markdown img ` ) . Attr ( "src" )
assert . True ( t , exists , "Image not found in markdown file" )
2023-04-22 17:56:27 -04:00
assert . Equal ( t , "/user2/repo1/media/branch/sub-home-md-img-check/docs/test-fake-img.jpg" , src )
2023-03-03 05:01:33 -05:00
}
2023-08-08 05:04:04 -04:00
func TestGeneratedSourceLink ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
t . Run ( "Rendered file" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/src/branch/master/README.md?display=source" )
resp := MakeRequest ( t , req , http . StatusOK )
doc := NewHTMLParser ( t , resp . Body )
dataURL , exists := doc . doc . Find ( ".copy-line-permalink" ) . Attr ( "data-url" )
assert . True ( t , exists )
assert . Equal ( t , "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source" , dataURL )
dataURL , exists = doc . doc . Find ( ".ref-in-new-issue" ) . Attr ( "data-url-param-body-link" )
assert . True ( t , exists )
assert . Equal ( t , "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source" , dataURL )
} )
t . Run ( "Non-Rendered file" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
session := loginUser ( t , "user27" )
req := NewRequest ( t , "GET" , "/user27/repo49/src/branch/master/test/test.txt" )
resp := session . MakeRequest ( t , req , http . StatusOK )
doc := NewHTMLParser ( t , resp . Body )
dataURL , exists := doc . doc . Find ( ".copy-line-permalink" ) . Attr ( "data-url" )
assert . True ( t , exists )
assert . Equal ( t , "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt" , dataURL )
dataURL , exists = doc . doc . Find ( ".ref-in-new-issue" ) . Attr ( "data-url-param-body-link" )
assert . True ( t , exists )
assert . Equal ( t , "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt" , dataURL )
} )
}
2024-01-07 05:20:22 -05:00
func TestViewCommit ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/commit/0123456789012345678901234567890123456789" )
req . Header . Add ( "Accept" , "text/html" )
resp := MakeRequest ( t , req , http . StatusNotFound )
assert . True ( t , test . IsNormalPageCompleted ( resp . Body . String ( ) ) , "non-existing commit should render 404 page" )
}
2023-11-14 13:24:20 -05:00
func TestCommitView ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
t . Run ( "Non-existent commit" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/commit/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" )
2024-01-04 17:29:28 -05:00
req . SetHeader ( "Accept" , "text/html" )
resp := MakeRequest ( t , req , http . StatusNotFound )
// Really ensure that 404 is being sent back.
doc := NewHTMLParser ( t , resp . Body )
doc . AssertElement ( t , ` [aria-label="Page Not Found"] ` , true )
2023-11-14 13:24:20 -05:00
} )
t . Run ( "Too short commit ID" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/commit/65f" )
MakeRequest ( t , req , http . StatusNotFound )
} )
t . Run ( "Short commit ID" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/commit/65f1" )
resp := MakeRequest ( t , req , http . StatusOK )
doc := NewHTMLParser ( t , resp . Body )
commitTitle := doc . Find ( ".commit-summary" ) . Text ( )
assert . Contains ( t , commitTitle , "Initial commit" )
} )
t . Run ( "Full commit ID" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d" )
resp := MakeRequest ( t , req , http . StatusOK )
doc := NewHTMLParser ( t , resp . Body )
commitTitle := doc . Find ( ".commit-summary" ) . Text ( )
assert . Contains ( t , commitTitle , "Initial commit" )
} )
}
2023-12-31 11:54:43 -05:00
func TestRepoHomeViewRedirect ( t * testing . T ) {
defer tests . PrepareTestEnv ( t ) ( )
t . Run ( "Code" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := MakeRequest ( t , req , http . StatusOK )
doc := NewHTMLParser ( t , resp . Body )
l := doc . Find ( "#repo-desc" ) . Length ( )
assert . Equal ( t , 1 , l )
} )
t . Run ( "No Code redirects to Issues" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
// Disable the Code unit
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } )
err := repo_service . UpdateRepositoryUnits ( db . DefaultContext , repo , nil , [ ] unit_model . Type {
unit_model . TypeCode ,
} )
assert . NoError ( t , err )
// The repo home should redirect to the built-in issue tracker
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := MakeRequest ( t , req , http . StatusSeeOther )
redir := resp . Header ( ) . Get ( "Location" )
assert . Equal ( t , "/user2/repo1/issues" , redir )
} )
t . Run ( "No Code and ExternalTracker redirects to Pulls" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
// Replace the internal tracker with an external one
// Disable Code, Projects, Packages, and Actions
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } )
err := repo_service . UpdateRepositoryUnits ( db . DefaultContext , repo , [ ] repo_model . RepoUnit { {
RepoID : repo . ID ,
Type : unit_model . TypeExternalTracker ,
Config : & repo_model . ExternalTrackerConfig {
ExternalTrackerURL : "https://example.com" ,
} ,
} } , [ ] unit_model . Type {
unit_model . TypeCode ,
unit_model . TypeIssues ,
unit_model . TypeProjects ,
unit_model . TypePackages ,
unit_model . TypeActions ,
} )
assert . NoError ( t , err )
// The repo home should redirect to pull requests
req := NewRequest ( t , "GET" , "/user2/repo1" )
resp := MakeRequest ( t , req , http . StatusSeeOther )
redir := resp . Header ( ) . Get ( "Location" )
assert . Equal ( t , "/user2/repo1/pulls" , redir )
} )
t . Run ( "Only external wiki results in 404" , func ( t * testing . T ) {
defer tests . PrintCurrentTest ( t ) ( )
// Replace the internal wiki with an external, and disable everything
// else.
repo := unittest . AssertExistsAndLoadBean ( t , & repo_model . Repository { ID : 1 } )
err := repo_service . UpdateRepositoryUnits ( db . DefaultContext , repo , [ ] repo_model . RepoUnit { {
RepoID : repo . ID ,
Type : unit_model . TypeExternalWiki ,
Config : & repo_model . ExternalWikiConfig {
ExternalWikiURL : "https://example.com" ,
} ,
} } , [ ] unit_model . Type {
unit_model . TypeCode ,
unit_model . TypeIssues ,
unit_model . TypeExternalTracker ,
unit_model . TypeProjects ,
unit_model . TypePackages ,
unit_model . TypeActions ,
unit_model . TypePullRequests ,
unit_model . TypeReleases ,
unit_model . TypeWiki ,
} )
assert . NoError ( t , err )
// The repo home ends up being 404
req := NewRequest ( t , "GET" , "/user2/repo1" )
req . Header . Set ( "Accept" , "text/html" )
resp := MakeRequest ( t , req , http . StatusNotFound )
// The external wiki is linked to from the 404 page
doc := NewHTMLParser ( t , resp . Body )
txt := strings . TrimSpace ( doc . Find ( ` a[href="https://example.com"] ` ) . Text ( ) )
assert . Equal ( t , "Wiki" , txt )
} )
}