Skip to content

Commit 7492251

Browse files
silverwindclaudewxiaoguang
authored
Fix relative-time RangeError (#37021)
`navigator.language` can be `undefined` in headless browsers (e.g. Playwright Firefox), causing `RangeError: invalid language tag: "undefined"` in `Intl.DateTimeFormat` within the `relative-time` web component. Also adds an e2e test that verifies `relative-time` renders correctly and a shared `assertNoJsError` helper. Bug is als present in https://github.com/github/relative-time-element but (incorrectly) masked there. Fixes: #25324 --------- Co-authored-by: Claude (Opus 4.6) <[email protected]> Co-authored-by: wxiaoguang <[email protected]>
1 parent b136a66 commit 7492251

File tree

7 files changed

+30
-9
lines changed

7 files changed

+30
-9
lines changed

modules/setting/setting.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ var (
2828
CfgProvider ConfigProvider
2929
IsWindows bool
3030

31-
// IsInTesting indicates whether the testing is running. A lot of unreliable code causes a lot of nonsense error logs during testing
32-
// TODO: this is only a temporary solution, we should make the test code more reliable
31+
// IsInTesting indicates whether the testing is running (unit test or integration test). It can be used for:
32+
// * Skip nonsense error logs during testing caused by unreliable code (TODO: this is only a temporary solution, we should make the test code more reliable)
33+
// * Panic in dev or testing mode to make the problem more obvious and easier to debug
34+
// * Mock some functions or options to make testing easier (eg: session store, time, URL detection, etc.)
3335
IsInTesting = false
3436
)
3537

@@ -57,6 +59,10 @@ func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
5759
return currentUser, runUser == currentUser
5860
}
5961

62+
func IsInE2eTesting() bool {
63+
return os.Getenv("GITEA_TEST_E2E") == "true"
64+
}
65+
6066
// PrepareAppDataPath creates app data directory if necessary
6167
func PrepareAppDataPath() error {
6268
// FIXME: There are too many calls to MkdirAll in old code. It is incorrect.

routers/web/web.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1740,7 +1740,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
17401740
m.Get("/swagger.v1.json", SwaggerV1Json)
17411741
}
17421742

1743-
if !setting.IsProd {
1743+
if !setting.IsProd || setting.IsInE2eTesting() {
17441744
m.Group("/devtest", func() {
17451745
m.Any("", devtest.List)
17461746
m.Any("/fetch-action-test", devtest.FetchActionTest)

templates/devtest/relative-time.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<div class="tw-grid tw-grid-cols-3 tw-gap-4">
44
<div>
55
<h2>Relative (auto)</h2>
6-
<div>now: <relative-time datetime="{{.TimeNow.Format "2006-01-02T15:04:05Z07:00"}}"></relative-time></div>
6+
<div>now: <relative-time data-testid="relative-time-now" datetime="{{.TimeNow.Format "2006-01-02T15:04:05Z07:00"}}"></relative-time></div>
77
<div>3m ago: <relative-time datetime="{{.TimePast3m.Format "2006-01-02T15:04:05Z07:00"}}"></relative-time></div>
88
<div>3h ago: <relative-time datetime="{{.TimePast3h.Format "2006-01-02T15:04:05Z07:00"}}"></relative-time></div>
99
<div>1d ago: <relative-time datetime="{{.TimePast1d.Format "2006-01-02T15:04:05Z07:00"}}"></relative-time></div>

tests/e2e/relative-time.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import {test, expect} from '@playwright/test';
2+
import {assertNoJsError} from './utils.ts';
3+
4+
test('relative-time renders without errors', async ({page}) => {
5+
await page.goto('/devtest/relative-time');
6+
const relativeTime = page.getByTestId('relative-time-now');
7+
await expect(relativeTime).toHaveAttribute('data-tooltip-content', /.+/);
8+
await expect(relativeTime).toHaveText('now');
9+
await assertNoJsError(page);
10+
});

tests/e2e/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ export async function login(page: Page, username = env.GITEA_TEST_E2E_USER, pass
104104
await expect(page.getByRole('link', {name: 'Sign In'})).toBeHidden();
105105
}
106106

107+
export async function assertNoJsError(page: Page) {
108+
await expect(page.locator('.js-global-error')).toHaveCount(0);
109+
}
110+
107111
export async function logout(page: Page) {
108112
await page.context().clearCookies(); // workaround issues related to fomantic dropdown
109113
await page.goto('/');

tools/test-e2e.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ LEVEL = Warn
4343
EOF
4444

4545
export GITEA_WORK_DIR="$WORK_DIR"
46+
export GITEA_TEST_E2E=true
4647

4748
# Start Gitea server
4849
echo "Starting Gitea server on port $FREE_PORT (workdir: $WORK_DIR)..."

web_src/js/webcomponents/relative-time.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,12 @@ class RelativeTime extends HTMLElement {
259259

260260
get #lang(): string {
261261
const lang = this.closest('[lang]')?.getAttribute('lang');
262-
if (!lang) return navigator.language;
263-
try {
264-
return new Intl.Locale(lang).toString();
265-
} catch {
266-
return navigator.language;
262+
if (lang) {
263+
try {
264+
return new Intl.Locale(lang).toString();
265+
} catch { /* invalid locale, fall through */ }
267266
}
267+
return navigator.language ?? 'en';
268268
}
269269

270270
get second(): 'numeric' | '2-digit' | undefined {

0 commit comments

Comments
 (0)