mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-07 00:30:19 +01:00
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
* fix: subdirectory redirects * fix: use path-segment boundary check when stripping BASE_URL prefix A bare `startsWith(BASE_URL)` matches on character prefix, not path segments. With BASE_URL="/chat", a path like "/chatroom/c/abc" would incorrectly strip to "room/c/abc" (no leading slash). Guard with an exact-match-or-slash check: `p === BASE_URL || p.startsWith(BASE_URL + '/')`. Also removes the dead `BASE_URL !== '/'` guard — module init already converts '/' to ''. * test: add path-segment boundary tests and clarify subdirectory coverage - Add /chatroom, /chatbot, /app/chatroom regression tests to verify BASE_URL stripping only matches on segment boundaries - Clarify useAuthRedirect subdirectory test documents React Router basename behavior (BASE_URL stripping tested in api-endpoints-subdir) - Use `delete proc.browser` instead of undefined assignment for cleanup - Add rationale to eslint-disable comment for isolateModules require * fix: use relative path and correct instructions in subdirectory test script - Replace hardcoded /home/danny/LibreChat/.env with repo-root-relative path so the script works from any checkout location - Update instructions to use production build (npm run build && npm run backend) since nginx proxies to :3080 which only serves the SPA after a full build, not during frontend:dev on :3090 * fix: skip pointless redirect_to=/ for root path and fix jsdom 26+ compat buildLoginRedirectUrl now returns plain /login when the resolved path is root — redirect_to=/ adds no value since / immediately redirects to /c/new after login anyway. Also rewrites api-endpoints.spec.ts to use window.history.replaceState instead of Object.defineProperty(window, 'location', ...) which jsdom 26+ no longer allows. * test: fix request-interceptor.spec.ts for jsdom 26+ compatibility Switch from jsdom to happy-dom environment which allows Object.defineProperty on window.location. jsdom 26+ made location non-configurable, breaking all 8 tests in this file. * chore: update browser property handling in api-endpoints-subdir test Changed the handling of the `proc.browser` property from deletion to setting it to false, ensuring compatibility with the current testing environment. * chore: update backend restart instructions in test subdirectory setup script Changed the instruction for restarting the backend from "npm run backend:dev" to "npm run backend" to reflect the correct command for the current setup. * refactor: ensure proper cleanup in loadModuleWithBase function Wrapped the module loading logic in a try-finally block to guarantee that the `proc.browser` property is reset to false and the base element is removed, improving reliability in the testing environment. * refactor: improve browser property handling in loadModuleWithBase function Revised the management of the `proc.browser` property to store the original value before modification, ensuring it is restored correctly after module loading. This enhances the reliability of the testing environment.
74 lines
2.8 KiB
TypeScript
74 lines
2.8 KiB
TypeScript
/**
|
|
* @jest-environment jsdom
|
|
*/
|
|
import { buildLoginRedirectUrl } from '../src/api-endpoints';
|
|
|
|
describe('buildLoginRedirectUrl', () => {
|
|
afterEach(() => {
|
|
window.history.replaceState({}, '', '/');
|
|
});
|
|
|
|
it('builds a login URL from explicit args', () => {
|
|
const result = buildLoginRedirectUrl('/c/new', '?q=hello', '');
|
|
expect(result).toBe('/login?redirect_to=%2Fc%2Fnew%3Fq%3Dhello');
|
|
});
|
|
|
|
it('encodes complex paths with query and hash', () => {
|
|
const result = buildLoginRedirectUrl('/c/new', '?q=hello&submit=true', '#section');
|
|
expect(result).toContain('redirect_to=');
|
|
const encoded = result.split('redirect_to=')[1];
|
|
expect(decodeURIComponent(encoded)).toBe('/c/new?q=hello&submit=true#section');
|
|
});
|
|
|
|
it('falls back to window.location when no args provided', () => {
|
|
window.history.replaceState({}, '', '/c/abc123?model=gpt-4#msg-5');
|
|
const result = buildLoginRedirectUrl();
|
|
const encoded = result.split('redirect_to=')[1];
|
|
expect(decodeURIComponent(encoded)).toBe('/c/abc123?model=gpt-4#msg-5');
|
|
});
|
|
|
|
it('returns plain /login when all location parts are empty (root)', () => {
|
|
window.history.replaceState({}, '', '/');
|
|
const result = buildLoginRedirectUrl();
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login when pathname is /login (prevents recursive redirect)', () => {
|
|
const result = buildLoginRedirectUrl('/login', '?redirect_to=%2Fc%2Fnew', '');
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login when window.location is already /login', () => {
|
|
window.history.replaceState({}, '', '/login?redirect_to=%2Fc%2Fabc');
|
|
const result = buildLoginRedirectUrl();
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login for /login sub-paths', () => {
|
|
const result = buildLoginRedirectUrl('/login/2fa', '', '');
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login for basename-prefixed /login (e.g. /librechat/login)', () => {
|
|
window.history.replaceState({}, '', '/librechat/login?redirect_to=%2Fc%2Fabc');
|
|
const result = buildLoginRedirectUrl();
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login for basename-prefixed /login sub-paths', () => {
|
|
const result = buildLoginRedirectUrl('/librechat/login/2fa', '', '');
|
|
expect(result).toBe('/login');
|
|
});
|
|
|
|
it('returns plain /login for root path (no pointless redirect_to=/)', () => {
|
|
const result = buildLoginRedirectUrl('/', '', '');
|
|
expect(result).toBe('/login');
|
|
expect(result).not.toContain('redirect_to');
|
|
});
|
|
|
|
it('does NOT match paths where "login" is a substring of a segment', () => {
|
|
const result = buildLoginRedirectUrl('/c/loginhistory', '', '');
|
|
expect(result).toContain('redirect_to=');
|
|
expect(decodeURIComponent(result.split('redirect_to=')[1])).toBe('/c/loginhistory');
|
|
});
|
|
});
|