Skip to content

Commit d332147

Browse files
committed
try workflow
1 parent c332661 commit d332147

File tree

11 files changed

+348
-67
lines changed

11 files changed

+348
-67
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: E2E Tests
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
e2e-tests:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 15
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '20'
22+
23+
- name: Start todo-app with Docker Compose
24+
working-directory: ./todo-app
25+
run: docker-compose up -d
26+
27+
- name: Wait for services to be ready
28+
run: |
29+
echo "Waiting for nginx to be ready on port 8080..."
30+
timeout 120 bash -c 'until curl -f http://localhost:8080 > /dev/null 2>&1; do sleep 2; done'
31+
echo "Services are ready!"
32+
33+
- name: Check running containers
34+
run: docker ps
35+
36+
- name: Install dependencies
37+
working-directory: ./todo-app
38+
run: npm ci
39+
40+
- name: Install Playwright browsers
41+
working-directory: ./todo-app
42+
run: npx playwright install --with-deps chromium
43+
44+
- name: Run Playwright tests
45+
working-directory: ./todo-app
46+
run: npm run test:e2e
47+
48+
- name: Upload Playwright report
49+
if: failure()
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: playwright-report
53+
path: todo-app/playwright-report/
54+
retention-days: 7
55+
56+
- name: Upload test results
57+
if: failure()
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: test-results
61+
path: todo-app/test-results/
62+
retention-days: 7
63+
64+
- name: Show container logs on failure
65+
if: failure()
66+
working-directory: ./todo-app
67+
run: |
68+
echo "=== Backend logs ==="
69+
docker-compose logs backend
70+
echo "=== Frontend logs ==="
71+
docker-compose logs app
72+
echo "=== Nginx logs ==="
73+
docker-compose logs nginx
74+
75+
- name: Clean up Docker containers
76+
if: always()
77+
working-directory: ./todo-app
78+
run: docker-compose down -v

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
node_modules/
22
.env
33
todo-app/redis_data/
4-
todo-app/mongo_data/
4+
todo-app/mongo_data/
5+
6+
# Playwright artifacts
7+
todo-app/test-results/
8+
todo-app/playwright-report/
9+
todo-app/playwright/.cache/

todo-app/package-lock.json

Lines changed: 79 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

todo-app/package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "todo-app-e2e-tests",
3+
"version": "1.0.0",
4+
"description": "E2E tests for todo-app using Playwright",
5+
"scripts": {
6+
"test:e2e": "playwright test",
7+
"test:e2e:ui": "playwright test --ui",
8+
"test:e2e:headed": "playwright test --headed",
9+
"test:e2e:debug": "playwright test --debug"
10+
},
11+
"keywords": ["playwright", "e2e", "testing"],
12+
"author": "",
13+
"license": "MIT",
14+
"devDependencies": {
15+
"@playwright/test": "^1.48.0"
16+
}
17+
}

todo-app/playwright.config.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { defineConfig, devices } from '@playwright/test';
2+
3+
/**
4+
* Playwright configuration for todo-app E2E tests
5+
* @see https://playwright.dev/docs/test-configuration
6+
*/
7+
export default defineConfig({
8+
testDir: './tests',
9+
/* Run tests in files in parallel */
10+
fullyParallel: true,
11+
/* Fail the build on CI if you accidentally left test.only in the source code. */
12+
forbidOnly: !!process.env.CI,
13+
/* Retry on CI only */
14+
retries: process.env.CI ? 2 : 0,
15+
/* Opt out of parallel tests on CI. */
16+
workers: process.env.CI ? 1 : undefined,
17+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
18+
reporter: [
19+
['html'],
20+
['list']
21+
],
22+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
23+
use: {
24+
/* Base URL to use in actions like `await page.goto('/')`. */
25+
baseURL: 'http://localhost:8080',
26+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
27+
trace: 'on-first-retry',
28+
screenshot: 'only-on-failure',
29+
},
30+
31+
/* Configure projects for major browsers */
32+
projects: [
33+
{
34+
name: 'chromium',
35+
use: { ...devices['Desktop Chrome'] },
36+
},
37+
],
38+
39+
/* Run your local dev server before starting the tests */
40+
// webServer: {
41+
// command: 'docker-compose up',
42+
// url: 'http://localhost:8080',
43+
// reuseExistingServer: !process.env.CI,
44+
// timeout: 120 * 1000,
45+
// },
46+
});

todo-app/tests/todo-app.spec.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test.describe('Todo App E2E Tests', () => {
4+
test.beforeEach(async ({ page }) => {
5+
// Navigate to the app before each test
6+
await page.goto('/');
7+
});
8+
9+
test('frontend loads and displays the todo application', async ({ page }) => {
10+
// Check that the page title or main heading is visible
11+
await expect(page).toHaveTitle(/Todo/i);
12+
13+
// Verify the main container or form is present
14+
const todoInput = page.getByRole('textbox');
15+
await expect(todoInput).toBeVisible();
16+
});
17+
18+
test('can add a new todo via UI', async ({ page }) => {
19+
// Fill in the todo input field
20+
const todoInput = page.getByRole('textbox');
21+
const testTodoText = `Test todo ${Date.now()}`;
22+
23+
await todoInput.fill(testTodoText);
24+
25+
// Submit the form (look for submit button or press Enter)
26+
await page.keyboard.press('Enter');
27+
28+
// Wait a moment for the todo to be added
29+
await page.waitForTimeout(500);
30+
31+
// Verify the todo appears in the list
32+
await expect(page.getByText(testTodoText)).toBeVisible();
33+
});
34+
35+
test('can toggle todo completion status', async ({ page }) => {
36+
// First, add a todo
37+
const todoInput = page.getByRole('textbox');
38+
const testTodoText = `Toggle test ${Date.now()}`;
39+
40+
await todoInput.fill(testTodoText);
41+
await page.keyboard.press('Enter');
42+
await page.waitForTimeout(500);
43+
44+
// Find and click the checkbox or completion button
45+
const todoItem = page.locator(`text=${testTodoText}`).locator('..');
46+
const checkbox = todoItem.getByRole('checkbox').or(todoItem.getByRole('button', { name: /complete|done|check/i }));
47+
48+
if (await checkbox.count() > 0) {
49+
await checkbox.first().click();
50+
await page.waitForTimeout(500);
51+
52+
// Verify the todo's state changed (could be strikethrough, different class, etc.)
53+
// This is a basic check - actual implementation may vary
54+
await expect(todoItem).toBeVisible();
55+
}
56+
});
57+
});
58+
59+
test.describe('Backend API Tests', () => {
60+
test('GET /api/todos returns todos list', async ({ request }) => {
61+
const response = await request.get('/api/todos');
62+
63+
expect(response.status()).toBe(200);
64+
65+
const todos = await response.json();
66+
expect(Array.isArray(todos)).toBe(true);
67+
});
68+
69+
test('POST /api/todos creates a new todo', async ({ request }) => {
70+
const newTodo = {
71+
text: `API test todo ${Date.now()}`,
72+
done: false
73+
};
74+
75+
const response = await request.post('/api/todos', {
76+
data: newTodo
77+
});
78+
79+
expect(response.status()).toBe(200);
80+
81+
const createdTodo = await response.json();
82+
expect(createdTodo.text).toBe(newTodo.text);
83+
expect(createdTodo).toHaveProperty('_id');
84+
});
85+
86+
test('GET /api/statistics returns added_todos count from Redis', async ({ request }) => {
87+
// First, create a todo to increment the counter
88+
await request.post('/api/todos', {
89+
data: { text: 'Stats test todo', done: false }
90+
});
91+
92+
// Then check statistics
93+
const response = await request.get('/api/statistics');
94+
95+
expect(response.status()).toBe(200);
96+
97+
const stats = await response.json();
98+
expect(stats).toHaveProperty('added_todos');
99+
expect(typeof stats.added_todos).toBe('number');
100+
expect(stats.added_todos).toBeGreaterThan(0);
101+
});
102+
103+
test('PUT /api/todos/:id updates a todo', async ({ request }) => {
104+
// First create a todo
105+
const createResponse = await request.post('/api/todos', {
106+
data: { text: 'Update test todo', done: false }
107+
});
108+
const createdTodo = await createResponse.json();
109+
110+
// Then update it
111+
const updateResponse = await request.put(`/api/todos/${createdTodo._id}`, {
112+
data: { text: 'Updated todo text', done: true }
113+
});
114+
115+
expect(updateResponse.status()).toBe(200);
116+
117+
const updatedTodo = await updateResponse.json();
118+
expect(updatedTodo.text).toBe('Updated todo text');
119+
expect(updatedTodo.done).toBe(true);
120+
});
121+
});

todo-app/todo-backend/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ npm-debug.log*
55
yarn-debug.log*
66
yarn-error.log*
77
mongo_data
8+
redis_data
89

910
# Runtime data
1011
pids
Binary file not shown.

0 commit comments

Comments
 (0)