Skip to content

Commit b25545b

Browse files
fix: e2e backend integration, Vite proxy conflict, and CI output path
- Fix port collision by splitting playwright webServer into separate API and frontend entries; add serve-e2e target without api:serve dependency - Fix API health check URL to use HTTP (dev HTTPS redirect is now prod-only) - Fix Vite proxy conflict: set Analog.js apiPrefix to '_analog' so its Nitro dev server no longer intercepts /api requests before the proxy - Switch Vite proxy target from https://localhost:60254 to http://localhost:60253 (avoids HTTPS cert issues in dev; redirect now production-only) - Add weather forecast API integration e2e test (table-row visibility) - Add home.e2e.spec.ts and about.e2e.spec.ts for Analog.js content pages - Fix CI/deploy output path: browser/ -> client/ (Analog.js default) Updates preview.yml, deploy.yml comment, and Program.cs PhysicalFileProvider Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2ad92b1 commit b25545b

9 files changed

Lines changed: 104 additions & 14 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ jobs:
6161
- name: Build web app (production)
6262
run: pnpm build:web-app:prod
6363

64-
# The .NET app serves the Angular SPA from apps/web-app/browser/ relative
64+
# The .NET app serves the Angular SPA from apps/web-app/client/ relative
6565
# to its working directory (see Program.cs PhysicalFileProvider). Both
6666
# outputs land in dist/ with the correct structure:
6767
# dist/ ← .NET publish output (Api.dll etc.)
68-
# dist/apps/web-app/browser/ ← Angular SPA
68+
# dist/apps/web-app/client/ ← Angular SPA
6969

7070
- name: Log in to Azure (OIDC)
7171
uses: azure/login@v2

.github/workflows/preview.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
run: pnpm nx build web-app --configuration preview
3737

3838
- name: Copy SWA routing config
39-
run: cp apps/web-app/src/staticwebapp.config.json dist/apps/web-app/browser/
39+
run: cp apps/web-app/src/staticwebapp.config.json dist/apps/web-app/client/
4040

4141
- name: Deploy to Azure Static Web Apps
4242
id: deploy
@@ -45,7 +45,7 @@ jobs:
4545
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
4646
repo_token: ${{ secrets.GITHUB_TOKEN }}
4747
action: upload
48-
app_location: dist/apps/web-app/browser
48+
app_location: dist/apps/web-app/client
4949
skip_app_build: true
5050
skip_deploy_on_missing_secrets: true
5151

apps/api/Api/Program.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,11 @@
143143
{
144144
app.UseExceptionHandler("/Error");
145145
app.UseHsts();
146+
app.UseHttpsRedirection();
146147
}
147148

148-
app.UseHttpsRedirection();
149-
150149
PhysicalFileProvider fileProvider = new PhysicalFileProvider(
151-
Path.Combine(Directory.GetCurrentDirectory(), "apps", "web-app", "browser")
150+
Path.Combine(Directory.GetCurrentDirectory(), "apps", "web-app", "client")
152151
);
153152
FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider();
154153
contentTypeProvider.Mappings[".webmanifest"] = "application/manifest+json";

apps/web-app-e2e/playwright.config.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,20 @@ export default defineConfig({
2424
trace: 'on-first-retry',
2525
},
2626
/* Run your local dev server before starting the tests */
27-
webServer: {
28-
command: 'npx nx run web-app:serve',
29-
url: 'http://localhost:4200',
30-
reuseExistingServer: !process.env.CI,
31-
cwd: workspaceRoot,
32-
},
27+
webServer: [
28+
{
29+
command: 'npx nx run api:serve',
30+
url: 'http://localhost:60253/health/live',
31+
reuseExistingServer: !process.env.CI,
32+
cwd: workspaceRoot,
33+
},
34+
{
35+
command: 'npx nx run web-app:serve-e2e',
36+
url: 'http://localhost:4200',
37+
reuseExistingServer: !process.env.CI,
38+
cwd: workspaceRoot,
39+
},
40+
],
3341
projects: [
3442
{
3543
name: 'chromium',
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test.describe('About page', () => {
4+
test('should load the about component', async ({ page }) => {
5+
await page.goto('/about');
6+
7+
await expect(page.getByTestId('app-about')).toBeVisible();
8+
});
9+
10+
test('should render the about heading', async ({ page }) => {
11+
await page.goto('/about');
12+
13+
await expect(
14+
page.getByRole('heading', { name: /about this starter/i }),
15+
).toBeVisible();
16+
});
17+
18+
test('should display the tech stack section', async ({ page }) => {
19+
await page.goto('/about');
20+
21+
await expect(
22+
page.getByRole('heading', { name: /tech stack/i }),
23+
).toBeVisible();
24+
});
25+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test.describe('Home page', () => {
4+
test('should load the home component', async ({ page }) => {
5+
await page.goto('/');
6+
7+
await expect(page.getByTestId('lib-home')).toBeVisible();
8+
});
9+
10+
test('should render markdown content', async ({ page }) => {
11+
await page.goto('/');
12+
13+
const markdown = page.getByTestId('page-markdown');
14+
await expect(markdown).toBeVisible();
15+
await expect(markdown).not.toBeEmpty();
16+
});
17+
18+
test('should display the hero heading', async ({ page }) => {
19+
await page.goto('/');
20+
21+
await expect(
22+
page.getByRole('heading', { name: /nx · angular · \.net/i }),
23+
).toBeVisible();
24+
});
25+
});

apps/web-app-e2e/src/weather-forecast.e2e.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,18 @@ test.describe('Weather Forecast page', () => {
2828
page.getByRole('button', { name: /get forecasts/i }),
2929
).toBeVisible();
3030
});
31+
32+
test('should fetch and display forecast rows from the API', async ({
33+
page,
34+
}) => {
35+
await page.goto('/weather-forecast');
36+
37+
// The store's onInit hook fetches forecasts automatically.
38+
// Row visibility confirms the API responded successfully.
39+
await expect(page.getByTestId('table-row').first()).toBeVisible({
40+
timeout: 10000,
41+
});
42+
const rowCount = await page.getByTestId('table-row').count();
43+
expect(rowCount).toBeGreaterThan(0);
44+
});
3145
});

apps/web-app/project.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@
4747
}
4848
}
4949
},
50+
"serve-e2e": {
51+
"executor": "@analogjs/platform:vite-dev-server",
52+
"continuous": true,
53+
"defaultConfiguration": "development",
54+
"options": {
55+
"buildTarget": "web-app:build",
56+
"port": 4200
57+
},
58+
"configurations": {
59+
"development": {
60+
"buildTarget": "web-app:build:development",
61+
"hmr": true
62+
},
63+
"production": {
64+
"buildTarget": "web-app:build:production"
65+
}
66+
}
67+
},
5068
"extract-i18n": {
5169
"executor": "@angular/build:extract-i18n",
5270
"options": {

apps/web-app/vite.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export default defineConfig(({ mode }) => {
2323
analog({
2424
ssr: false,
2525
static: true,
26+
apiPrefix: '_analog',
2627
prerender: {
2728
routes: [],
2829
},
@@ -112,7 +113,7 @@ export default defineConfig(({ mode }) => {
112113
server: {
113114
proxy: {
114115
'/api': {
115-
target: 'https://localhost:60254',
116+
target: 'http://localhost:60253',
116117
secure: false,
117118
},
118119
},

0 commit comments

Comments
 (0)