Skip to content

Commit 4ddeef6

Browse files
AvivAbachigithub-actions[bot]NoamGaash
authored
fix: set base URL to '/' and add comprehensive tests (#1393)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Aviv <AvivAbachi@users.noreply.github.com> Co-authored-by: Noam Gaash <NoamGaash@users.noreply.github.com>
1 parent 6416a75 commit 4ddeef6

5 files changed

Lines changed: 128 additions & 6 deletions

File tree

.env

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
# solves issues with stylis-plugin-rtl : https://github.com/styled-components/stylis-plugin-rtl/issues/35#issuecomment-1550877823
22
GENERATE_SOURCEMAP=false
3+
4+
# Stride API endpoint for bus routing and transit data
35
VITE_STRIDE_API=https://open-bus-stride-api.hasadna.org.il
4-
VITE_BACKEND_API=https://open-bus-backend.k8s.hasadna.org.il
6+
7+
# Backend API endpoint for application data and services
8+
VITE_BACKEND_API=https://open-bus-backend.k8s.hasadna.org.il
9+
10+
# Optional: URL for preview environment
11+
# VITE_BASE_PATH=
12+
13+
# Optional: Enable coverage reporting for tests
14+
# VITE_COVERAGE=

.github/workflows/build.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ permissions:
77
issues: write
88

99
env:
10-
VITE_MSW_S3_URL: https://s3.amazonaws.com/noam-gaash.co.il/${{ github.run_id }}/open-bus/${{ github.run_number }}/storybook/mockServiceWorker.js
10+
VITE_BASE_PATH: /noam-gaash.co.il/${{ github.run_id }}/open-bus/${{ github.run_number }}/
1111

1212
jobs:
1313
build:
@@ -24,6 +24,8 @@ jobs:
2424
- name: Run install
2525
run: npm ci
2626
- name: Build
27+
env:
28+
VITE_BASE_PATH: ${{ env.VITE_BASE_PATH }}
2729
run: npm run build
2830
- name: Upload artifact (build)
2931
uses: actions/upload-artifact@v4
@@ -43,6 +45,8 @@ jobs:
4345
- name: Run install
4446
run: npm ci
4547
- name: Build Storybook
48+
env:
49+
VITE_BASE_PATH: ${{ env.VITE_BASE_PATH }}
4650
run: npm run build-storybook -- -o dist/storybook
4751
- name: Upload artifact (storybook)
4852
uses: actions/upload-artifact@v4

src/routes/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,6 @@ window.addEventListener('vite:preloadError', () => {
177177

178178
const routes = createRoutesFromElements(getRoutesList())
179179

180-
const router = createBrowserRouter(routes)
180+
const router = createBrowserRouter(routes, { basename: import.meta.env.VITE_BASE_PATH })
181181

182182
export default router

tests/baseUrl.spec.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { expect, setupTest, test } from './utils'
2+
3+
test.describe('Base URL configuration tests', () => {
4+
test('assets should load from root path on nested routes', async ({ page }) => {
5+
await setupTest(page)
6+
7+
// Navigate to a nested route (e.g., /profile/:id)
8+
// We'll use a direct navigation to simulate the issue scenario
9+
await page.goto('/profile/8235701')
10+
11+
// Wait for the page to load
12+
await page.waitForLoadState('networkidle')
13+
14+
// Check that JavaScript assets are loaded from the correct path
15+
const scriptTags = await page.locator('script[src]').all()
16+
const scriptSources = await Promise.all(scriptTags.map((tag) => tag.getAttribute('src')))
17+
18+
// Filter for internal scripts with absolute paths
19+
const assetScripts = scriptSources.filter(
20+
(src) => src && src.startsWith('/') && !src.startsWith('http'),
21+
)
22+
23+
// Verify that we found asset scripts to test
24+
expect(assetScripts.length).toBeGreaterThan(0)
25+
26+
// Verify that asset paths start with / (absolute) and not from current path
27+
const currentPath = new URL(page.url()).pathname
28+
for (const src of assetScripts) {
29+
if (src) {
30+
expect(src.startsWith('/')).toBeTruthy()
31+
expect(src.startsWith(currentPath + '/')).toBeFalsy()
32+
}
33+
}
34+
35+
// Also verify that internal script resources loaded successfully (no 404s)
36+
const failedRequests: string[] = []
37+
page.on('requestfailed', (request) => {
38+
if (
39+
request.resourceType() === 'script' &&
40+
request.url().startsWith('http://localhost:3000/')
41+
) {
42+
failedRequests.push(request.url())
43+
}
44+
})
45+
46+
// Reload the page to trigger all resource loads again
47+
await page.reload()
48+
await page.waitForLoadState('networkidle')
49+
50+
// Check that no internal script requests failed
51+
expect(failedRequests.length).toBe(0)
52+
})
53+
54+
test('assets should load correctly on dashboard page', async ({ page }) => {
55+
await setupTest(page)
56+
57+
// Navigate to dashboard (a top-level route)
58+
await page.goto('/dashboard')
59+
await page.waitForLoadState('networkidle')
60+
61+
// Check that JavaScript assets are loaded from the correct path
62+
const scriptTags = await page.locator('script[src]').all()
63+
const scriptSources = await Promise.all(scriptTags.map((tag) => tag.getAttribute('src')))
64+
65+
// Filter for internal scripts with absolute paths
66+
const assetScripts = scriptSources.filter(
67+
(src) => src && src.startsWith('/') && !src.startsWith('http'),
68+
)
69+
70+
// Verify that we found asset scripts to test
71+
expect(assetScripts.length).toBeGreaterThan(0)
72+
73+
// Verify that asset paths start with / (absolute)
74+
for (const src of assetScripts) {
75+
if (src) {
76+
expect(src.startsWith('/')).toBeTruthy()
77+
}
78+
}
79+
})
80+
81+
test('CSS assets should load from root path on nested routes', async ({ page }) => {
82+
await setupTest(page)
83+
84+
// Navigate to a nested route
85+
await page.goto('/profile/8235701')
86+
await page.waitForLoadState('networkidle')
87+
88+
// Check that CSS assets are loaded from the correct path
89+
const linkTags = await page.locator('link[rel="stylesheet"]').all()
90+
const linkHrefs = await Promise.all(linkTags.map((tag) => tag.getAttribute('href')))
91+
92+
// Filter for internal links with absolute paths
93+
const assetLinks = linkHrefs.filter(
94+
(href) => href && href.startsWith('/') && !href.startsWith('http'),
95+
)
96+
97+
// If there are asset links, verify their paths
98+
if (assetLinks.length > 0) {
99+
// Verify that asset paths start with / (absolute) and not from current path
100+
const currentPath = new URL(page.url()).pathname
101+
for (const href of assetLinks) {
102+
if (href) {
103+
expect(href.startsWith('/')).toBeTruthy()
104+
expect(href.startsWith(currentPath + '/')).toBeFalsy()
105+
}
106+
}
107+
}
108+
})
109+
})

vite.config.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import react from '@vitejs/plugin-react-oxc'
2-
import { loadEnv } from 'vite'
2+
import { defineConfig, loadEnv } from 'vite'
33
import IstanbulPlugin from 'vite-plugin-istanbul'
4-
import { defineConfig } from 'vitest/config'
54

65
// https://vitejs.dev/config/
76
export default defineConfig(({ mode }) => {
87
const env = loadEnv(mode, process.cwd())
98

109
return {
11-
base: env?.ASSET_URL || '',
10+
base: env?.VITE_BASE_PATH || '/',
1211
plugins: [
1312
react(),
1413
...(env?.VITE_COVERAGE

0 commit comments

Comments
 (0)