Files
Gitea/web_src/js/modules/errors.test.ts
T
silverwind 40079c7c09 fix(ui): ignore code line anchors below 1, show JS errors in vite dev mode (#39432) (#40087)
Backport https://github.com/go-gitea/gitea/pull/39432

- A `#L0` URL hash made `selectRange` index the line list at -1 and
throw inside `initRepoCodeView`, which aborted every init function after
it on the page. Line numbers below 1 now select nothing.
- The JS error filter only accepted stacks under the asset prefix, but
the vite dev server serves the sources from `/web_src/`, so dev mode
dropped every error without showing a banner. Outside production, the
filter now also accepts stacks from `/web_src/`.
2026-10-30 19:07:17 +00:00

54 lines
2.8 KiB
TypeScript

import {isGiteaError, processWindowErrorEvent, showGlobalErrorMessage} from './errors.ts';
beforeEach(() => {
document.body.innerHTML = '<div class="page-content"></div>';
});
test('isGiteaError', () => {
const {origin} = window.location;
expect(isGiteaError('', '')).toBe(true);
expect(isGiteaError('moz-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('safari-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('safari-web-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('chrome-extension://abc/content.js', '')).toBe(false);
expect(isGiteaError('https://other-site.com/script.js', '')).toBe(false);
expect(isGiteaError(`${origin}/some/page`, '')).toBe(true);
expect(isGiteaError(`${origin}/assets/js/index.abc123.js`, '')).toBe(true);
expect(isGiteaError('', `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
expect(isGiteaError('', `Error\n at https://other-site.com/script.js:1:1`)).toBe(false);
expect(isGiteaError('', `Error\n at ${origin}/assets/js/index.abc123.js:1:1`)).toBe(true);
expect(isGiteaError('', `Error\n at ${origin}/web_src/js/index.ts:1:1`)).toBe(false);
expect(isGiteaError(`${origin}/assets/js/index.js`, `Error\n at chrome-extension://abc/content.js:1:1`)).toBe(false);
vi.spyOn(window.config, 'runModeIsProd', 'get').mockReturnValue(false);
expect(isGiteaError('', `Error\n at ${origin}/web_src/js/index.ts:1:1`)).toBe(true);
vi.restoreAllMocks();
});
test('showGlobalErrorMessage', () => {
showGlobalErrorMessage('test msg 1');
showGlobalErrorMessage('test msg 2');
showGlobalErrorMessage('test msg 1'); // duplicated
expect(document.body.innerHTML).toContain('>test msg 1 (2)<');
expect(document.body.innerHTML).toContain('>test msg 2<');
expect(document.querySelectorAll('.js-global-error').length).toEqual(2);
});
test('processWindowErrorEvent renders stack trace in details', () => {
const error = new Error('boom');
error.stack = `Error: boom\n at fn (${window.location.origin}/assets/js/index.js:1:1)`;
processWindowErrorEvent({error, type: 'error'} as ErrorEvent & PromiseRejectionEvent);
expect(document.querySelector('.js-global-error summary')!.textContent).toContain('JavaScript error: boom');
expect(document.querySelector('.js-global-error pre')!.textContent).toContain('/assets/js/index.js:1:1');
});
test('processWindowErrorEvent falls back to message without stack', () => {
processWindowErrorEvent({
error: {message: 'script error'}, type: 'error',
filename: `${window.location.origin}/assets/js/x.js`, lineno: 5, colno: 10,
} as ErrorEvent & PromiseRejectionEvent);
const msgText = document.querySelector('.js-global-error .ui.message')!.textContent;
expect(msgText).toContain('JavaScript error: script error');
expect(msgText).toContain('@ 5:10');
});