pruebas e2e
This commit is contained in:
@@ -1,13 +0,0 @@
|
|||||||
target/
|
|
||||||
.git/
|
|
||||||
node_modules/
|
|
||||||
.next/
|
|
||||||
web/studio/node_modules/
|
|
||||||
web/experience/node_modules/
|
|
||||||
web/studio/.next/
|
|
||||||
web/experience/.next/
|
|
||||||
services/*/target/
|
|
||||||
*.log
|
|
||||||
.env
|
|
||||||
.DS_Store
|
|
||||||
.vscode/
|
|
||||||
@@ -62,7 +62,12 @@ docker compose up -d --build
|
|||||||
- **Rendimiento Bajo (Orange)**: P% to P+9%
|
- **Rendimiento Bajo (Orange)**: P% to P+9%
|
||||||
- **Rendimiento Medio (Yellow)**: P+10% to P+15%
|
- **Rendimiento Medio (Yellow)**: P+10% to P+15%
|
||||||
- **Buen Rendimiento (Green)**: P+16% to 90%
|
- **Buen Rendimiento (Green)**: P+16% to 90%
|
||||||
|
- **Buen Rendimiento (Green)**: P+16% to 90%
|
||||||
- **Excelente (Blue)**: 91%+
|
- **Excelente (Blue)**: 91%+
|
||||||
|
- **Automated Certificate Generation**:
|
||||||
|
- HTML-based customizable certificate templates
|
||||||
|
- Automatic download button upon passing a course
|
||||||
|
- PDF generation for print/save
|
||||||
|
|
||||||
### 📈 Analytics & Insights
|
### 📈 Analytics & Insights
|
||||||
- **Instructor Analytics Dashboard**:
|
- **Instructor Analytics Dashboard**:
|
||||||
@@ -85,6 +90,10 @@ docker compose up -d --build
|
|||||||
- **Students**: Course enrollment, lesson consumption, progress tracking
|
- **Students**: Course enrollment, lesson consumption, progress tracking
|
||||||
- **Service-to-Service Authorization**: Secure internal API calls with token validation
|
- **Service-to-Service Authorization**: Secure internal API calls with token validation
|
||||||
- **Audit Logging**: All CMS mutations recorded for compliance and debugging
|
- **Audit Logging**: All CMS mutations recorded for compliance and debugging
|
||||||
|
- **Admin Audit Dashboard**:
|
||||||
|
- Visual interface to view system logs
|
||||||
|
- Diff viewer for JSON changes
|
||||||
|
- Advanced filtering by user and action
|
||||||
|
|
||||||
### 🚀 Service Integration
|
### 🚀 Service Integration
|
||||||
- **Automatic Sync**: One-click publish from CMS to LMS
|
- **Automatic Sync**: One-click publish from CMS to LMS
|
||||||
@@ -218,6 +227,8 @@ openccb/
|
|||||||
- ✅ **Dynamic Passing Thresholds**: Customizable pass marks with 5-tier performance visualization
|
- ✅ **Dynamic Passing Thresholds**: Customizable pass marks with 5-tier performance visualization
|
||||||
- ✅ **Role-Based Access Control**: Admin, Instructor, and Student roles with granular permissions
|
- ✅ **Role-Based Access Control**: Admin, Instructor, and Student roles with granular permissions
|
||||||
- ✅ **Enhanced Progress Dashboard**: Real-time weighted grades and visual performance bars
|
- ✅ **Enhanced Progress Dashboard**: Real-time weighted grades and visual performance bars
|
||||||
|
- ✅ **Certificate System**: Custom HTML templates and automated generation
|
||||||
|
- ✅ **Quality Assurance**: Automated End-to-End (E2E) testing pipeline with Playwright
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
NEXT_PUBLIC_LMS_API_URL: http://localhost:3002
|
NEXT_PUBLIC_LMS_API_URL: http://localhost:3002
|
||||||
|
|
||||||
|
e2e:
|
||||||
|
build:
|
||||||
|
context: ./e2e
|
||||||
|
environment:
|
||||||
|
- STUDIO_URL=http://studio:3000
|
||||||
|
- EXPERIENCE_URL=http://experience:3003
|
||||||
|
depends_on:
|
||||||
|
- studio
|
||||||
|
- experience
|
||||||
|
volumes:
|
||||||
|
- ./e2e/tests:/e2e/tests
|
||||||
|
- ./e2e/playwright-report:/e2e/playwright-report
|
||||||
|
profiles: [ "test" ]
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
uploads_data:
|
uploads_data:
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
|
||||||
|
|
||||||
|
WORKDIR /e2e
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Default command, can be overridden
|
||||||
|
CMD ["npx", "playwright", "test"]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "openccb-e2e",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"test": "playwright test",
|
||||||
|
"test:ui": "playwright test --ui",
|
||||||
|
"test:debug": "playwright test --debug"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "1.40.0",
|
||||||
|
"@types/node": "^20.10.0",
|
||||||
|
"typescript": "^5.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,44 @@
|
|||||||
|
import { defineConfig, devices } from '@playwright/test';
|
||||||
|
|
||||||
|
// Use environment variables for base URLs, with fallbacks for local dev vs docker
|
||||||
|
const STUDIO_URL = process.env.STUDIO_URL || 'http://studio:3000';
|
||||||
|
const EXPERIENCE_URL = process.env.EXPERIENCE_URL || 'http://experience:3003';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
fullyParallel: true,
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: process.env.CI ? 2 : 0,
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
reporter: 'html',
|
||||||
|
use: {
|
||||||
|
trace: 'on-first-retry',
|
||||||
|
screenshot: 'only-on-failure',
|
||||||
|
video: 'retain-on-failure',
|
||||||
|
},
|
||||||
|
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
name: 'setup',
|
||||||
|
testMatch: /global\.setup\.ts/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'studio',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Chrome'],
|
||||||
|
baseURL: STUDIO_URL,
|
||||||
|
},
|
||||||
|
testMatch: /.*instructor.*\.spec\.ts/,
|
||||||
|
dependencies: ['setup'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'experience',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Chrome'],
|
||||||
|
baseURL: EXPERIENCE_URL,
|
||||||
|
},
|
||||||
|
testMatch: /.*student.*\.spec\.ts/,
|
||||||
|
dependencies: ['setup'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { test as setup } from '@playwright/test';
|
||||||
|
|
||||||
|
setup('check services are up', async ({ request }) => {
|
||||||
|
// We could ping health endpoints here
|
||||||
|
// const studio = await request.get('http://studio:3000');
|
||||||
|
// expect(studio.ok()).toBeTruthy();
|
||||||
|
console.log('Setup complete - proceeding to tests');
|
||||||
|
});
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Instructor Flow', () => {
|
||||||
|
test('should login, create course, add content, and publish', async ({ page }) => {
|
||||||
|
const email = `instructor_${Date.now()}@test.com`;
|
||||||
|
|
||||||
|
// 0. Register (since DB might be empty)
|
||||||
|
await page.goto('/auth/register');
|
||||||
|
await page.fill('[placeholder="Instructor Name"]', 'E2E Instructor');
|
||||||
|
await page.fill('[placeholder="instructor@openccb.com"]', email); // or input[type="email"]
|
||||||
|
await page.fill('[placeholder="••••••••"]', 'password123'); // or input[type="password"]
|
||||||
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
|
// Wait for navigation - Register automatically logs in and redirects to /
|
||||||
|
// Increase timeout for cold starts in CI/Docker
|
||||||
|
await expect(page).toHaveURL('/', { timeout: 15000 });
|
||||||
|
|
||||||
|
// Verify dashboard loaded
|
||||||
|
await expect(page.locator('h2')).toContainText('My Courses', { timeout: 10000 });
|
||||||
|
|
||||||
|
// 2. Create Course
|
||||||
|
// Usamos manejador de dialogo para el prompt
|
||||||
|
const courseName = 'Playwright E2E Course ' + Date.now();
|
||||||
|
page.on('dialog', dialog => dialog.accept(courseName));
|
||||||
|
await page.click('button:has-text("New Course")');
|
||||||
|
|
||||||
|
// Esperar a que aparezca el nuevo curso y hacer clic
|
||||||
|
await page.waitForTimeout(1000); // Wait for API
|
||||||
|
await page.click('text=Playwright E2E Course');
|
||||||
|
|
||||||
|
// 3. Add Module
|
||||||
|
await page.click('button:has-text("Add Module")');
|
||||||
|
await page.fill('[placeholder="Module Title"]', 'Module 1: Basics');
|
||||||
|
await page.click('button:has-text("Create Module")');
|
||||||
|
|
||||||
|
// 4. Add Lesson
|
||||||
|
await page.click('button:has-text("Add Lesson")');
|
||||||
|
await page.fill('[placeholder="Lesson Title"]', 'Intro Lesson');
|
||||||
|
// Select video type (assuming it's default or select dropdown)
|
||||||
|
await page.click('button:has-text("Create Lesson")');
|
||||||
|
|
||||||
|
// 5. Publish
|
||||||
|
await page.click('button:has-text("Publish Course")');
|
||||||
|
|
||||||
|
// Confirm publish
|
||||||
|
// Assuming there is a confirmation or toast
|
||||||
|
// await expect(page.locator('text=Published successfully')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Student Flow', () => {
|
||||||
|
test('should login and view catalog', async ({ page }) => {
|
||||||
|
// 1. Register/Login
|
||||||
|
// For simplicity, we assume registration or reuse existing
|
||||||
|
await page.goto('/auth/login');
|
||||||
|
|
||||||
|
// Register link?
|
||||||
|
// await page.click('text=Sign up');
|
||||||
|
// ... fill registration ...
|
||||||
|
|
||||||
|
// OR just login if we seed the DB.
|
||||||
|
// For E2E on fresh DB, we might need to register first.
|
||||||
|
|
||||||
|
// Let's try to register a new user every time to be safe
|
||||||
|
// Let's try to register a new user every time to be safe
|
||||||
|
const email = `student_${Date.now()}@test.com`;
|
||||||
|
await page.goto('/auth/register');
|
||||||
|
await page.fill('[placeholder="John Doe"]', 'Test Student');
|
||||||
|
await page.fill('[placeholder="name@company.com"]', email);
|
||||||
|
await page.fill('[placeholder="••••••••"]', 'password123');
|
||||||
|
await page.click('button[type="submit"]');
|
||||||
|
|
||||||
|
// Should redirect to dashboard/catalog
|
||||||
|
await expect(page).toHaveURL('/', { timeout: 15000 });
|
||||||
|
await expect(page.locator('h1')).toContainText('Available Courses', { timeout: 10000 });
|
||||||
|
|
||||||
|
// Check if the course from instructor flow is visible (might need refresh)
|
||||||
|
await page.reload();
|
||||||
|
// await expect(page.locator('text=Playwright E2E Course')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
+6
-6
@@ -32,7 +32,7 @@
|
|||||||
- [x] Role-specific permissions and UI
|
- [x] Role-specific permissions and UI
|
||||||
- [x] Token-based authorization for protected endpoints
|
- [x] Token-based authorization for protected endpoints
|
||||||
- [x] **Audit Logging**: All CMS mutations tracked
|
- [x] **Audit Logging**: All CMS mutations tracked
|
||||||
- [ ] **Audit UI**: Admin interface to view audit logs
|
- [x] **Audit UI**: Admin interface to view audit logs
|
||||||
|
|
||||||
## Phase 4: LMS Experience & Grading ✅
|
## Phase 4: LMS Experience & Grading ✅
|
||||||
- [x] **Student Portal (Experience)**:
|
- [x] **Student Portal (Experience)**:
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
- [x] Configurable passing percentage per course
|
- [x] Configurable passing percentage per course
|
||||||
- [x] 5-tier performance visualization
|
- [x] 5-tier performance visualization
|
||||||
- [x] Color-coded feedback (Reprobado to Excelente)
|
- [x] Color-coded feedback (Reprobado to Excelente)
|
||||||
- [ ] **Certificates**: Automated certificate generation upon completion
|
- [x] **Certificates**: Automated certificate generation upon completion
|
||||||
|
|
||||||
## Phase 5: Analytics & Insights ✅
|
## Phase 5: Analytics & Insights ✅
|
||||||
- [x] **Instructor Analytics Dashboard**:
|
- [x] **Instructor Analytics Dashboard**:
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
- ✅ Enhanced student progress dashboard
|
- ✅ Enhanced student progress dashboard
|
||||||
|
|
||||||
**Next Priorities**:
|
**Next Priorities**:
|
||||||
1. Automated certificate generation
|
1. Multi-tenancy support
|
||||||
2. Audit log UI for administrators
|
2. AI-powered content generation
|
||||||
3. Multi-tenancy support
|
3. Gamification (Badges & Achievements)
|
||||||
4. AI-powered content generation
|
4. Advanced analytics & reporting
|
||||||
|
|||||||
Reference in New Issue
Block a user