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 Medio (Yellow)**: P+10% to P+15%
|
||||
- **Buen Rendimiento (Green)**: P+16% to 90%
|
||||
- **Buen Rendimiento (Green)**: P+16% to 90%
|
||||
- **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
|
||||
- **Instructor Analytics Dashboard**:
|
||||
@@ -85,6 +90,10 @@ docker compose up -d --build
|
||||
- **Students**: Course enrollment, lesson consumption, progress tracking
|
||||
- **Service-to-Service Authorization**: Secure internal API calls with token validation
|
||||
- **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
|
||||
- **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
|
||||
- ✅ **Role-Based Access Control**: Admin, Instructor, and Student roles with granular permissions
|
||||
- ✅ **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
|
||||
|
||||
|
||||
@@ -52,6 +52,20 @@ services:
|
||||
environment:
|
||||
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:
|
||||
postgres_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] Token-based authorization for protected endpoints
|
||||
- [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 ✅
|
||||
- [x] **Student Portal (Experience)**:
|
||||
@@ -55,7 +55,7 @@
|
||||
- [x] Configurable passing percentage per course
|
||||
- [x] 5-tier performance visualization
|
||||
- [x] Color-coded feedback (Reprobado to Excelente)
|
||||
- [ ] **Certificates**: Automated certificate generation upon completion
|
||||
- [x] **Certificates**: Automated certificate generation upon completion
|
||||
|
||||
## Phase 5: Analytics & Insights ✅
|
||||
- [x] **Instructor Analytics Dashboard**:
|
||||
@@ -122,7 +122,7 @@
|
||||
- ✅ Enhanced student progress dashboard
|
||||
|
||||
**Next Priorities**:
|
||||
1. Automated certificate generation
|
||||
2. Audit log UI for administrators
|
||||
3. Multi-tenancy support
|
||||
4. AI-powered content generation
|
||||
1. Multi-tenancy support
|
||||
2. AI-powered content generation
|
||||
3. Gamification (Badges & Achievements)
|
||||
4. Advanced analytics & reporting
|
||||
|
||||
Reference in New Issue
Block a user