Skip to content

Commit 6f610c0

Browse files
GeekTrainerCopilot
andcommitted
Restructure project into app/ directory
Move client/, server/, and scripts/ directories under app/ to consolidate application code. Update all references in dependabot config, gitignore, workshop content, and filepath comments. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ab3e09f commit 6f610c0

37 files changed

Lines changed: 1534 additions & 17 deletions

.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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ 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/
4545

4646
# e2e test database
47-
server/e2e_test_dogshelter.db
47+
app/server/e2e_test_dogshelter.db

app/client/.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
node_modules
3+
dist

app/client/Dockerfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM node:lts AS runtime
2+
WORKDIR /app
3+
4+
COPY . .
5+
6+
RUN npm install
7+
RUN npm run build
8+
9+
ENV HOST=0.0.0.0
10+
ENV PORT=4321
11+
EXPOSE 4321
12+
CMD node ./dist/server/entry.mjs

app/client/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Astro Starter Kit: Basics
2+
3+
```sh
4+
npm create astro@latest -- --template basics
5+
```
6+
7+
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
8+
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
9+
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
10+
11+
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
12+
13+
![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
14+
15+
## 🚀 Project Structure
16+
17+
Inside of your Astro project, you'll see the following folders and files:
18+
19+
```text
20+
/
21+
├── public/
22+
│ └── favicon.svg
23+
├── src/
24+
│ ├── layouts/
25+
│ │ └── Layout.astro
26+
│ └── pages/
27+
│ └── index.astro
28+
└── package.json
29+
```
30+
31+
To learn more about the folder structure of an Astro project, refer to [our guide on project structure](https://docs.astro.build/en/basics/project-structure/).
32+
33+
## 🧞 Commands
34+
35+
All commands are run from the root of the project, from a terminal:
36+
37+
| Command | Action |
38+
| :------------------------ | :----------------------------------------------- |
39+
| `npm install` | Installs dependencies |
40+
| `npm run dev` | Starts local dev server at `localhost:4321` |
41+
| `npm run build` | Build your production site to `./dist/` |
42+
| `npm run preview` | Preview your build locally, before deploying |
43+
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
44+
| `npm run astro -- --help` | Get help using the Astro CLI |
45+
46+
## 👀 Want to learn more?
47+
48+
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

app/client/e2e-tests/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# End-to-End Tests for Tailspin Shelter
2+
3+
This directory contains Playwright end-to-end tests for the Tailspin Shelter website.
4+
5+
## Test Files
6+
7+
- `homepage.spec.ts` - Tests for the main homepage functionality
8+
- `about.spec.ts` - Tests for the about page
9+
- `dog-details.spec.ts` - Tests for individual dog detail pages
10+
- `api-integration.spec.ts` - Tests for API integration and error handling
11+
12+
## Running Tests
13+
14+
### Prerequisites
15+
16+
Make sure you have installed dependencies:
17+
```bash
18+
npm install
19+
```
20+
21+
You also need Python 3 with Flask dependencies installed:
22+
```bash
23+
pip install -r ../server/requirements.txt
24+
```
25+
26+
### Running Tests
27+
28+
```bash
29+
# Run all tests
30+
npm run test:e2e
31+
32+
# Run tests with UI mode (for debugging)
33+
npm run test:e2e:ui
34+
35+
# Run tests in headed mode (see browser)
36+
npm run test:e2e:headed
37+
38+
# Debug tests
39+
npm run test:e2e:debug
40+
```
41+
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+
53+
## Test Coverage
54+
55+
The tests cover the following core functionality:
56+
57+
### Homepage Tests
58+
- Page loads with correct title and content
59+
- Dog list displays properly
60+
61+
### About Page Tests
62+
- About page content displays correctly
63+
- Navigation back to homepage works
64+
65+
### Dog Details Tests
66+
- Navigation from homepage to dog details
67+
- Full dog details display correctly
68+
- Navigation back from dog details to homepage
69+
- Handling of invalid dog IDs
70+
71+
### API Integration Tests
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
76+
77+
## Configuration
78+
79+
Tests are configured in `../playwright.config.ts` and automatically start the Flask and Astro servers before running tests.
80+
81+
The tests run against:
82+
- Client (Astro): http://localhost:4321
83+
- Server (Flask): http://localhost:5100

app/client/e2e-tests/about.spec.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('About Page', () => {
4+
test('should load about page and display content', async ({ page }) => {
5+
await page.goto('/about');
6+
7+
// Check that the page title is correct
8+
await expect(page).toHaveTitle(/About - Tailspin Shelter/);
9+
10+
// Check that the main heading is visible
11+
await expect(page.getByRole('heading', { name: 'About Tailspin Shelter' })).toBeVisible();
12+
13+
// Check that content is visible
14+
await expect(page.getByText('Nestled in the heart of Seattle')).toBeVisible();
15+
await expect(page.getByText('The name "Tailspin" reflects')).toBeVisible();
16+
17+
// Check the fictional organization note
18+
await expect(page.getByText('Tailspin Shelter is a fictional organization')).toBeVisible();
19+
});
20+
21+
test('should navigate back to homepage from about page', async ({ page }) => {
22+
await page.goto('/about');
23+
24+
// Click the "Back to Dogs" button
25+
await page.getByRole('link', { name: 'Back to Dogs' }).click();
26+
27+
// Should be redirected to homepage
28+
await expect(page).toHaveURL('/');
29+
await expect(page.getByRole('heading', { name: 'Welcome to Tailspin Shelter' })).toBeVisible();
30+
});
31+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('Dog Details', () => {
4+
test('should navigate to dog details from homepage', async ({ page }) => {
5+
await page.goto('/');
6+
7+
const firstDogCard = page.getByTestId('dog-card').first();
8+
const dogName = await page.getByTestId('dog-name').first().textContent();
9+
10+
await firstDogCard.click();
11+
12+
await expect(page).toHaveURL(/\/dog\/\d+/);
13+
await expect(page).toHaveTitle(/Dog Details - Tailspin Shelter/);
14+
await expect(page.getByTestId('dog-details')).toBeVisible();
15+
await expect(page.getByTestId('dog-name')).toHaveText(dogName!);
16+
});
17+
18+
test('should display full dog details for Buddy', async ({ page }) => {
19+
await page.goto('/dog/1');
20+
21+
await expect(page.getByTestId('dog-details')).toBeVisible();
22+
await expect(page.getByTestId('dog-name')).toHaveText('Buddy');
23+
await expect(page.getByTestId('dog-breed')).toContainText('Golden Retriever');
24+
await expect(page.getByTestId('dog-age')).toContainText('3');
25+
await expect(page.getByTestId('dog-gender')).toContainText('Male');
26+
await expect(page.getByTestId('dog-status')).toHaveText('Available');
27+
await expect(page.getByTestId('dog-description')).toContainText('friendly and loyal');
28+
});
29+
30+
test('should navigate back to homepage from dog details', async ({ page }) => {
31+
await page.goto('/dog/1');
32+
33+
await page.getByTestId('back-link').click();
34+
35+
await expect(page).toHaveURL('/');
36+
await expect(page.getByRole('heading', { name: 'Welcome to Tailspin Shelter' })).toBeVisible();
37+
});
38+
39+
test('should handle invalid dog ID gracefully', async ({ page }) => {
40+
await page.goto('/dog/99999');
41+
42+
await expect(page).toHaveTitle(/Dog Details - Tailspin Shelter/);
43+
await expect(page.getByTestId('error-message')).toBeVisible();
44+
await expect(page.getByTestId('back-link')).toBeVisible();
45+
});
46+
});

app/client/playwright.config.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
import path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
6+
const serverDir = path.resolve(__dirname, '..', 'server');
7+
const testDbPath = path.join(serverDir, 'e2e_test_dogshelter.db');
8+
const flaskPort = 5100;
9+
const astroDevPort = 4321;
10+
11+
export default defineConfig({
12+
testDir: './e2e-tests',
13+
fullyParallel: true,
14+
forbidOnly: !!process.env.CI,
15+
retries: process.env.CI ? 2 : 0,
16+
workers: process.env.CI ? 1 : undefined,
17+
reporter: 'html',
18+
use: {
19+
baseURL: `http://localhost:${astroDevPort}`,
20+
trace: 'on-first-retry',
21+
},
22+
projects: [
23+
{
24+
name: 'chromium',
25+
use: { ...devices['Desktop Chrome'] },
26+
},
27+
],
28+
webServer: [
29+
{
30+
command: `cd ${serverDir} && python3 utils/seed_test_database.py && DATABASE_PATH=${testDbPath} python3 app.py`,
31+
url: `http://localhost:${flaskPort}/api/dogs`,
32+
reuseExistingServer: !process.env.CI,
33+
timeout: 30_000,
34+
},
35+
{
36+
command: `API_SERVER_URL=http://localhost:${flaskPort} npm run dev -- --no-clearScreen`,
37+
url: `http://localhost:${astroDevPort}`,
38+
reuseExistingServer: !process.env.CI,
39+
timeout: 30_000,
40+
},
41+
],
42+
});

app/client/public/favicon.svg

Lines changed: 9 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)