Skip to content

Commit c180d23

Browse files
authored
Merge pull request #179 from github-samples/simplify-client-app
Simplify client: remove Svelte, use pure Astro with SSR data fetching
2 parents 761ead3 + fdaa14a commit c180d23

79 files changed

Lines changed: 1870 additions & 2149 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
version: 2
99
updates:
1010
- package-ecosystem: npm
11-
directory: /client
11+
directory: /app/client
1212
schedule:
1313
interval: weekly
1414
groups:

.gitignore

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ flask_session/
4040
htmlcov/
4141

4242
# playwright
43-
client/test-results/
44-
client/playwright-report/
43+
app/client/test-results/
44+
app/client/playwright-report/
45+
.playwright-mcp/
46+
47+
# e2e test database
48+
app/server/e2e_test_dogshelter.db
49+
50+
# azure
4551
.azure

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Pets workshop
22

3-
This repository contains the project for three guided workshops to explore various GitHub features. The project is a website for a fictional dog shelter, with a [Flask](https://flask.palletsprojects.com/en/stable/) backend using [SQLAlchemy](https://www.sqlalchemy.org/) and [Astro](https://astro.build/) frontend using [Svelte](https://svelte.dev/) for dynamic pages.
3+
This repository contains the project for three guided workshops to explore various GitHub features. The project is a website for a fictional dog shelter, with a [Flask](https://flask.palletsprojects.com/en/stable/) backend using [SQLAlchemy](https://www.sqlalchemy.org/) and an [Astro](https://astro.build/) frontend using [Tailwind CSS](https://tailwindcss.com/).
44

55
The available workshops are:
66

File renamed without changes.
File renamed without changes.

app/client/astro.config.mjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @ts-check
2+
process.env.ASTRO_TELEMETRY_DISABLED = '1';
3+
import { defineConfig } from 'astro/config';
4+
import tailwindcss from '@tailwindcss/vite';
5+
import node from '@astrojs/node';
6+
import fs from 'node:fs';
7+
import path from 'node:path';
8+
9+
// Allow Vite to serve files from the real node_modules path when it is symlinked
10+
const nodeModulesPath = path.resolve('node_modules');
11+
const realNodeModulesPath = fs.realpathSync(nodeModulesPath);
12+
const fsAllow = ['..'];
13+
if (realNodeModulesPath !== nodeModulesPath) {
14+
fsAllow.push(path.dirname(realNodeModulesPath));
15+
}
16+
17+
// https://astro.build/config
18+
export default defineConfig({
19+
output: 'server',
20+
vite: {
21+
plugins: [tailwindcss()],
22+
server: {
23+
fs: {
24+
allow: fsAllow,
25+
},
26+
},
27+
},
28+
adapter: node({
29+
mode: 'standalone'
30+
}),
31+
});
Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ Make sure you have installed dependencies:
1818
npm install
1919
```
2020

21+
You also need Python 3 with Flask dependencies installed:
22+
```bash
23+
pip install -r ../server/requirements.txt
24+
```
25+
2126
### Running Tests
2227

2328
```bash
@@ -34,33 +39,44 @@ npm run test:e2e:headed
3439
npm run test:e2e:debug
3540
```
3641

42+
## Test Architecture
43+
44+
Tests run against the real Flask server with a separate test database seeded with deterministic data. When Playwright starts, it:
45+
46+
1. Seeds a test database (`e2e_test_dogshelter.db` in the server directory) with known dogs and breeds
47+
2. Starts the Flask server using the test database
48+
3. Starts the Astro dev server pointing at the Flask server
49+
4. Runs all e2e tests against the live application
50+
51+
The test data is defined in `../server/utils/seed_test_database.py`.
52+
3753
## Test Coverage
3854

3955
The tests cover the following core functionality:
4056

4157
### Homepage Tests
4258
- Page loads with correct title and content
4359
- Dog list displays properly
44-
- Loading states work correctly
45-
- Error handling for API failures
4660

4761
### About Page Tests
4862
- About page content displays correctly
4963
- Navigation back to homepage works
5064

5165
### Dog Details Tests
5266
- Navigation from homepage to dog details
67+
- Full dog details display correctly
5368
- Navigation back from dog details to homepage
5469
- Handling of invalid dog IDs
5570

5671
### API Integration Tests
57-
- Successful API responses
58-
- Empty dog list handling
59-
- Network error handling
72+
- Dogs render correctly on the homepage
73+
- Dog details render correctly
74+
- 404 handling for non-existent dogs
75+
- Navigation from card to detail page
6076

6177
## Configuration
6278

63-
Tests are configured in `../playwright.config.ts` and automatically start the application servers using the existing `scripts/start-app.sh` script before running tests.
79+
Tests are configured in `../playwright.config.ts` and automatically start the Flask and Astro servers before running tests.
6480

6581
The tests run against:
6682
- Client (Astro): http://localhost:4321
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('API Integration', () => {
4+
test('should render dogs from the API on the homepage', async ({ page }) => {
5+
await page.goto('/');
6+
7+
const dogCards = page.getByTestId('dog-card');
8+
await expect(dogCards).toHaveCount(6);
9+
10+
await expect(page.getByTestId('dog-name').nth(0)).toHaveText('Buddy');
11+
await expect(page.getByTestId('dog-breed').nth(0)).toHaveText('Golden Retriever');
12+
13+
await expect(page.getByTestId('dog-name').nth(1)).toHaveText('Luna');
14+
await expect(page.getByTestId('dog-breed').nth(1)).toHaveText('Husky');
15+
16+
await expect(page.getByTestId('dog-name').nth(2)).toHaveText('Max');
17+
await expect(page.getByTestId('dog-breed').nth(2)).toHaveText('German Shepherd');
18+
});
19+
20+
test('should render dog details from the API', async ({ page }) => {
21+
await page.goto('/dog/1');
22+
23+
await expect(page.getByTestId('dog-details')).toBeVisible();
24+
await expect(page.getByTestId('dog-name')).toHaveText('Buddy');
25+
await expect(page.getByTestId('dog-breed')).toContainText('Golden Retriever');
26+
await expect(page.getByTestId('dog-age')).toContainText('3');
27+
await expect(page.getByTestId('dog-gender')).toContainText('Male');
28+
await expect(page.getByTestId('dog-status')).toHaveText('Available');
29+
});
30+
31+
test('should return 404 details for non-existent dog', async ({ page }) => {
32+
await page.goto('/dog/99999');
33+
34+
await expect(page.getByTestId('error-message')).toBeVisible();
35+
await expect(page.getByTestId('error-message')).toContainText('not found');
36+
});
37+
38+
test('should link from dog card to detail page', async ({ page }) => {
39+
await page.goto('/');
40+
41+
const firstCard = page.getByTestId('dog-card').first();
42+
await firstCard.click();
43+
44+
await expect(page).toHaveURL(/\/dog\/1$/);
45+
await expect(page.getByTestId('dog-details')).toBeVisible();
46+
});
47+
});

0 commit comments

Comments
 (0)