diff --git a/.claude/settings.local.json b/.claude/settings.local.json index f1099f56..11565d2b 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -46,15 +46,8 @@ "mcp__plugin_context-mode_context-mode__ctx_stats", "mcp__plugin_context-mode_context-mode__ctx_execute_file", "Bash(git checkout *)", - "Bash(python -m py_compile backend/tests/conftest.py)", - "Bash(python -m py_compile backend/tests/test_users.py)", - "Bash(python *)", - "Bash(python3.12 -m venv backend/venv)", - "Bash(backend/venv/bin/pip install *)", - "Bash(sudo apt-get *)", - "Bash(PYTHONPATH=/data/programare_AI/tfm_ainventory:/data/programare_AI/tfm_ainventory/backend backend/venv/bin/pytest backend/tests/test_items.py::TestItemCRUD::test_create_item -v)", - "Bash(PYTHONPATH=/data/programare_AI/tfm_ainventory:/data/programare_AI/tfm_ainventory/backend backend/venv/bin/pytest backend/tests/test_items.py::TestItemCRUD::test_create_item -vv)", - "Bash(git tag *)" + "Bash(git stash *)", + "Bash(python -m pytest backend/tests/ -v --tb=short)" ] } } diff --git a/backend/tests/test_items.py b/backend/tests/test_items.py index 89fccca6..ee11cc97 100644 --- a/backend/tests/test_items.py +++ b/backend/tests/test_items.py @@ -12,7 +12,7 @@ class TestItemCRUD: json={ "name": "Test Item", "category": "Electronics", - "item_type": "Component", + "type": "Component", "quantity": 10, "barcode": "123456789", "part_number": "PN-12345" @@ -141,7 +141,7 @@ class TestItemValidation: json={ "name": "Item2", "category": "B", - "item_type": "Type", + "type": "Type", "quantity": 5, "barcode": "UNIQUE123", "part_number": "PN2" @@ -156,7 +156,7 @@ class TestItemValidation: json={ "name": "Test", "category": "A", - "item_type": "Type", + "type": "Type", "quantity": -5, "barcode": "123", "part_number": "PN" diff --git a/backend/tests/test_users.py b/backend/tests/test_users.py index 7f90d4e4..22050c2b 100644 --- a/backend/tests/test_users.py +++ b/backend/tests/test_users.py @@ -9,7 +9,7 @@ class TestUserAuthentication: def test_login_ldap_success(self, test_client, mock_ldap): """Test successful LDAP login.""" response = test_client.post( - "/api/auth/login", + "/api/users/login", json={"username": "testuser", "password": "password123"} ) assert response.status_code == status.HTTP_200_OK @@ -21,7 +21,7 @@ class TestUserAuthentication: mock_ldap.bind.side_effect = Exception("Invalid credentials") response = test_client.post( - "/api/auth/login", + "/api/users/login", json={"username": "testuser", "password": "wrongpassword"} ) assert response.status_code == status.HTTP_401_UNAUTHORIZED @@ -29,13 +29,12 @@ class TestUserAuthentication: def test_login_local_password(self, test_client, test_db): """Test local password authentication (fallback).""" from backend.models import User - from backend.auth import hash_password + from backend.routers.users import get_password_hash # Create local user user = User( username="localuser", - email="local@test.com", - hashed_password=hash_password("password123"), + hashed_password=get_password_hash("password123"), role="user", origin="local" ) @@ -43,7 +42,7 @@ class TestUserAuthentication: test_db.commit() response = test_client.post( - "/api/auth/login", + "/api/users/login", json={"username": "localuser", "password": "password123"} ) assert response.status_code == status.HTTP_200_OK @@ -59,7 +58,7 @@ class TestUserCRUD: "/api/users", json={ "username": "newuser", - "email": "new@test.com", + "password": "NewPass123!", "role": "user" }, headers={"Authorization": f"Bearer {admin_token}"} @@ -67,7 +66,7 @@ class TestUserCRUD: assert response.status_code == status.HTTP_201_CREATED data = response.json() assert data["username"] == "newuser" - assert data["email"] == "new@test.com" + assert data["role"] == "user" def test_create_user_non_admin_denied(self, test_client, user_token): """Test that non-admin users cannot create users.""" @@ -75,7 +74,7 @@ class TestUserCRUD: "/api/users", json={ "username": "newuser", - "email": "new@test.com", + "password": "Pass123!", "role": "user" }, headers={"Authorization": f"Bearer {user_token}"} @@ -88,7 +87,6 @@ class TestUserCRUD: user = User( username="testuser", - email="test@test.com", hashed_password="hashed", role="user", origin="local" @@ -105,8 +103,8 @@ class TestUserCRUD: """Test listing all users.""" from backend.models import User - user1 = User(username="user1", email="user1@test.com", hashed_password="h", role="user", origin="local") - user2 = User(username="user2", email="user2@test.com", hashed_password="h", role="user", origin="local") + user1 = User(username="user1", hashed_password="h", role="user", origin="local") + user2 = User(username="user2", hashed_password="h", role="user", origin="local") test_db.add_all([user1, user2]) test_db.commit() @@ -119,24 +117,24 @@ class TestUserCRUD: """Test updating user (admin only).""" from backend.models import User - user = User(username="testuser", email="old@test.com", hashed_password="h", role="user", origin="local") + user = User(username="testuser", hashed_password="h", role="user", origin="local") test_db.add(user) test_db.commit() response = test_client.put( f"/api/users/{user.id}", - json={"email": "new@test.com", "role": "admin"}, + json={"username": "updateduser", "role": "admin"}, headers={"Authorization": f"Bearer {admin_token}"} ) assert response.status_code == status.HTTP_200_OK data = response.json() - assert data["email"] == "new@test.com" + assert data["role"] == "admin" def test_delete_user_admin_only(self, test_client, test_db, admin_token): """Test deleting user (admin only).""" from backend.models import User - user = User(username="testuser", email="test@test.com", hashed_password="h", role="user", origin="local") + user = User(username="testuser", hashed_password="h", role="user", origin="local") test_db.add(user) test_db.commit() user_id = user.id diff --git a/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/error-context.md new file mode 100644 index 00000000..36a17042 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should handle network errors gracefully +- Location: e2e/workflows/1-login.spec.ts:181:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-0bb23-e-network-errors-gracefully-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/error-context.md new file mode 100644 index 00000000..11547a50 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should allow switching between LDAP and local login tabs +- Location: e2e/workflows/1-login.spec.ts:146:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-1065a-n-LDAP-and-local-login-tabs-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/error-context.md new file mode 100644 index 00000000..18822765 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should auto-login when clicking user from list +- Location: e2e/workflows/1-login.spec.ts:215:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-19d2a-hen-clicking-user-from-list-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/error-context.md new file mode 100644 index 00000000..4897970c --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should successfully login with valid local user credentials +- Location: e2e/workflows/1-login.spec.ts:81:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-1b0d7-alid-local-user-credentials-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/error-context.md new file mode 100644 index 00000000..d1b698cc --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should reject invalid local user credentials +- Location: e2e/workflows/1-login.spec.ts:66:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-1def4-alid-local-user-credentials-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/error-context.md new file mode 100644 index 00000000..64b2ac62 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should successfully login with valid LDAP credentials +- Location: e2e/workflows/1-login.spec.ts:52:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-24db1-with-valid-LDAP-credentials-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/error-context.md new file mode 100644 index 00000000..8989388b --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should maintain session across page reloads +- Location: e2e/workflows/1-login.spec.ts:105:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-2cf04-session-across-page-reloads-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/error-context.md new file mode 100644 index 00000000..4772f0df --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should display login form with username and password fields +- Location: e2e/workflows/1-login.spec.ts:28:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-6d596-sername-and-password-fields-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/error-context.md new file mode 100644 index 00000000..35897dd9 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should show admin button for admin users +- Location: e2e/workflows/1-login.spec.ts:137:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-77e03-dmin-button-for-admin-users-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/error-context.md new file mode 100644 index 00000000..60856744 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should show user identity after successful login +- Location: e2e/workflows/1-login.spec.ts:93:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-8b7ad-tity-after-successful-login-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-8fef9-login-preference-on-revisit-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-8fef9-login-preference-on-revisit-chromium/error-context.md new file mode 100644 index 00000000..5001eaf6 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-8fef9-login-preference-on-revisit-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should remember login preference on revisit +- Location: e2e/workflows/1-login.spec.ts:165:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/error-context.md new file mode 100644 index 00000000..d8edbca0 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should reject invalid LDAP credentials +- Location: e2e/workflows/1-login.spec.ts:41:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-a6e06-ct-invalid-LDAP-credentials-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/error-context.md new file mode 100644 index 00000000..132bb58c --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should display identity check overlay on app load +- Location: e2e/workflows/1-login.spec.ts:16:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-ba9e9-y-check-overlay-on-app-load-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/error-context.md new file mode 100644 index 00000000..cf8c3abb --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should display user list in local login tab +- Location: e2e/workflows/1-login.spec.ts:202:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-sho-d35b6-ser-list-in-local-login-tab-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/error-context.md new file mode 100644 index 00000000..9c13c59a --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should reject empty login credentials +- Location: e2e/workflows/1-login.spec.ts:32:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-should-reject-empty-login-credentials-chromium/test-failed-1.png differ diff --git a/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/error-context.md b/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/error-context.md new file mode 100644 index 00000000..f5acca49 --- /dev/null +++ b/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 1-login.spec.ts >> Login Workflow >> should support logout functionality +- Location: e2e/workflows/1-login.spec.ts:120:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data'; + 5 | + 6 | test.describe('Login Workflow', () => { + 7 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 8 | + 9 | test.beforeEach(async ({ page }) => { + 10 | // Navigate to login page +> 11 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 12 | // Wait for identity check overlay + 13 | await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 }); + 14 | }); + 15 | + 16 | test('should display identity check overlay on app load', async ({ page }) => { + 17 | const overlay = page.locator('[data-testid="identity-check-overlay"]'); + 18 | await expect(overlay).toBeVisible(); + 19 | + 20 | // Verify tabs are available + 21 | const ldapTab = page.locator('[data-testid="ldap-login-tab"]'); + 22 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 23 | + 24 | await expect(ldapTab).toBeVisible(); + 25 | await expect(localTab).toBeVisible(); + 26 | }); + 27 | + 28 | test('should display login form with username and password fields', async ({ page }) => { + 29 | await assertions.assertLoginFormVisible(page); + 30 | }); + 31 | + 32 | test('should reject empty login credentials', async ({ page }) => { + 33 | const submitButton = page.locator('[data-testid="login-submit"]'); + 34 | await submitButton.click(); + 35 | + 36 | // Should show validation error + 37 | const errorMessage = page.locator('[data-testid="toast-error"]'); + 38 | await expect(errorMessage).toBeVisible({ timeout: 3000 }); + 39 | }); + 40 | + 41 | test('should reject invalid LDAP credentials', async ({ page }) => { + 42 | await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL); + 43 | + 44 | // Should show error message + 45 | const errorToast = page.locator('[data-testid="toast-error"]'); + 46 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 47 | + 48 | // Should still be on login page + 49 | await expect(page).toHaveURL(BASE_URL); + 50 | }); + 51 | + 52 | test('should successfully login with valid LDAP credentials', async ({ page }) => { + 53 | // Skip if LDAP is not configured in test environment + 54 | test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment'); + 55 | + 56 | await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL); + 57 | + 58 | // Verify we're authenticated + 59 | await assertions.assertUserAuthenticated(page, BASE_URL); + 60 | + 61 | // Verify token is stored + 62 | const token = await auth.getAuthToken(page); + 63 | expect(token).toBeTruthy(); + 64 | }); + 65 | + 66 | test('should reject invalid local user credentials', async ({ page }) => { + 67 | // Switch to local user tab + 68 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 69 | await localTab.click(); + 70 | + 71 | // Try to login with invalid credentials + 72 | await page.fill('[data-testid="local-username-input"]', 'invalid_user'); + 73 | await page.fill('[data-testid="local-password-input"]', 'wrong_password'); + 74 | await page.click('[data-testid="local-login-submit"]'); + 75 | + 76 | // Should show error + 77 | const errorToast = page.locator('[data-testid="toast-error"]'); + 78 | await expect(errorToast).toBeVisible({ timeout: 5000 }); + 79 | }); + 80 | + 81 | test('should successfully login with valid local user credentials', async ({ page }) => { + 82 | // Switch to local user tab + 83 | const localTab = page.locator('[data-testid="local-login-tab"]'); + 84 | await localTab.click(); + 85 | + 86 | // Login with valid credentials + 87 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 88 | + 89 | // Verify authenticated + 90 | await assertions.assertUserAuthenticated(page, BASE_URL); + 91 | }); + 92 | + 93 | test('should show user identity after successful login', async ({ page }) => { + 94 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 95 | + 96 | // Check that user info is displayed + 97 | const userDisplay = page.locator('[data-testid="user-display"]'); + 98 | await expect(userDisplay).toBeVisible(); + 99 | + 100 | // Verify username is shown + 101 | const username = await userDisplay.textContent(); + 102 | expect(username).toContain(LOCAL_USERS.admin.username); + 103 | }); + 104 | + 105 | test('should maintain session across page reloads', async ({ page }) => { + 106 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 107 | await assertions.assertUserAuthenticated(page, BASE_URL); + 108 | + 109 | // Reload page + 110 | await page.reload(); + 111 | +``` \ No newline at end of file diff --git a/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/test-failed-1.png b/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/1-login-Login-Workflow-should-support-logout-functionality-chromium/test-failed-1.png differ diff --git a/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/error-context.md b/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/error-context.md new file mode 100644 index 00000000..d980af15 --- /dev/null +++ b/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/error-context.md @@ -0,0 +1,137 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 2-scan-adjust.spec.ts >> Scan and Adjust Workflow >> should display scan input field +- Location: e2e/workflows/2-scan-adjust.spec.ts:32:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import * as helpers from '../utils/helpers'; + 5 | import { LOCAL_USERS, TEST_ITEMS } from '../fixtures/test-data'; + 6 | + 7 | test.describe('Scan and Adjust Workflow', () => { + 8 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 9 | + 10 | test.beforeEach(async ({ page }) => { + 11 | // Navigate to app and login +> 12 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 13 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 14 | await assertions.assertUserAuthenticated(page, BASE_URL); + 15 | + 16 | // Navigate to scanner page + 17 | await page.goto(`${BASE_URL}/scanner`); + 18 | await assertions.assertScannerReady(page); + 19 | }); + 20 | + 21 | test('should display scanner interface with camera view', async ({ page }) => { + 22 | await assertions.assertScannerReady(page); + 23 | + 24 | // Verify camera controls + 25 | const zoomButton = page.locator('[data-testid="zoom-control"]'); + 26 | const cameraIndicator = page.locator('[data-testid="camera-indicator"]'); + 27 | + 28 | await expect(zoomButton).toBeVisible(); + 29 | await expect(cameraIndicator).toBeVisible(); + 30 | }); + 31 | + 32 | test('should display scan input field', async ({ page }) => { + 33 | const scanInput = page.locator('[data-testid="scan-input"]'); + 34 | await expect(scanInput).toBeVisible(); + 35 | await expect(scanInput).toBeFocused(); + 36 | }); + 37 | + 38 | test('should handle barcode scan and match to inventory item', async ({ page }) => { + 39 | // Simulate barcode scan by entering barcode in input + 40 | const scanInput = page.locator('[data-testid="scan-input"]'); + 41 | + 42 | // Enter first test item's barcode + 43 | await scanInput.fill(TEST_ITEMS[0].barcode); + 44 | await scanInput.press('Enter'); + 45 | + 46 | // Should show stock adjustment form + 47 | await assertions.assertStockAdjustmentVisible(page, TEST_ITEMS[0].name); + 48 | + 49 | // Verify item details are shown + 50 | const itemName = page.locator('[data-testid="adjustment-item-name"]'); + 51 | await expect(itemName).toContainText(TEST_ITEMS[0].name); + 52 | }); + 53 | + 54 | test('should default to check-in operation', async ({ page }) => { + 55 | const scanInput = page.locator('[data-testid="scan-input"]'); + 56 | await scanInput.fill(TEST_ITEMS[0].barcode); + 57 | await scanInput.press('Enter'); + 58 | + 59 | // Check-in radio should be selected + 60 | const checkInRadio = page.locator('[data-testid="operation-checkin"]'); + 61 | await expect(checkInRadio).toBeChecked(); + 62 | }); + 63 | + 64 | test('should allow switching between check-in and check-out', async ({ page }) => { + 65 | const scanInput = page.locator('[data-testid="scan-input"]'); + 66 | await scanInput.fill(TEST_ITEMS[0].barcode); + 67 | await scanInput.press('Enter'); + 68 | + 69 | // Switch to check-out + 70 | const checkOutRadio = page.locator('[data-testid="operation-checkout"]'); + 71 | await checkOutRadio.click(); + 72 | await expect(checkOutRadio).toBeChecked(); + 73 | + 74 | // Switch back to check-in + 75 | const checkInRadio = page.locator('[data-testid="operation-checkin"]'); + 76 | await checkInRadio.click(); + 77 | await expect(checkInRadio).toBeChecked(); + 78 | }); + 79 | + 80 | test('should allow quantity adjustment', async ({ page }) => { + 81 | const scanInput = page.locator('[data-testid="scan-input"]'); + 82 | await scanInput.fill(TEST_ITEMS[0].barcode); + 83 | await scanInput.press('Enter'); + 84 | + 85 | // Change quantity + 86 | const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); + 87 | await quantityInput.fill('10'); + 88 | + 89 | // Verify value changed + 90 | const value = await helpers.getInputValue(page, '[data-testid="adjustment-quantity-input"]'); + 91 | expect(value).toBe('10'); + 92 | }); + 93 | + 94 | test('should reject invalid quantities', async ({ page }) => { + 95 | const scanInput = page.locator('[data-testid="scan-input"]'); + 96 | await scanInput.fill(TEST_ITEMS[0].barcode); + 97 | await scanInput.press('Enter'); + 98 | + 99 | // Try invalid quantity + 100 | const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); + 101 | await quantityInput.fill('-5'); + 102 | + 103 | // Submit should be disabled or show error + 104 | const submitButton = page.locator('[data-testid="adjustment-submit"]'); + 105 | if (await submitButton.isEnabled()) { + 106 | await submitButton.click(); + 107 | const errorToast = page.locator('[data-testid="toast-error"]'); + 108 | await expect(errorToast).toBeVisible({ timeout: 3000 }); + 109 | } + 110 | }); + 111 | + 112 | test('should submit stock adjustment successfully', async ({ page }) => { +``` \ No newline at end of file diff --git a/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/test-failed-1.png b/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/2-scan-adjust-Scan-and-Adj-4dfc2-ld-display-scan-input-field-chromium/test-failed-1.png differ diff --git a/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/error-context.md b/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/error-context.md new file mode 100644 index 00000000..c85a9427 --- /dev/null +++ b/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/error-context.md @@ -0,0 +1,137 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: 2-scan-adjust.spec.ts >> Scan and Adjust Workflow >> should display scanner interface with camera view +- Location: e2e/workflows/2-scan-adjust.spec.ts:21:7 + +# Error details + +``` +Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ +Call log: + - navigating to "http://localhost:3000/", waiting until "load" + +``` + +# Test source + +```ts + 1 | import { test, expect } from '@playwright/test'; + 2 | import * as auth from '../fixtures/auth'; + 3 | import * as assertions from '../utils/assertions'; + 4 | import * as helpers from '../utils/helpers'; + 5 | import { LOCAL_USERS, TEST_ITEMS } from '../fixtures/test-data'; + 6 | + 7 | test.describe('Scan and Adjust Workflow', () => { + 8 | const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + 9 | + 10 | test.beforeEach(async ({ page }) => { + 11 | // Navigate to app and login +> 12 | await page.goto(BASE_URL); + | ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000/ + 13 | await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + 14 | await assertions.assertUserAuthenticated(page, BASE_URL); + 15 | + 16 | // Navigate to scanner page + 17 | await page.goto(`${BASE_URL}/scanner`); + 18 | await assertions.assertScannerReady(page); + 19 | }); + 20 | + 21 | test('should display scanner interface with camera view', async ({ page }) => { + 22 | await assertions.assertScannerReady(page); + 23 | + 24 | // Verify camera controls + 25 | const zoomButton = page.locator('[data-testid="zoom-control"]'); + 26 | const cameraIndicator = page.locator('[data-testid="camera-indicator"]'); + 27 | + 28 | await expect(zoomButton).toBeVisible(); + 29 | await expect(cameraIndicator).toBeVisible(); + 30 | }); + 31 | + 32 | test('should display scan input field', async ({ page }) => { + 33 | const scanInput = page.locator('[data-testid="scan-input"]'); + 34 | await expect(scanInput).toBeVisible(); + 35 | await expect(scanInput).toBeFocused(); + 36 | }); + 37 | + 38 | test('should handle barcode scan and match to inventory item', async ({ page }) => { + 39 | // Simulate barcode scan by entering barcode in input + 40 | const scanInput = page.locator('[data-testid="scan-input"]'); + 41 | + 42 | // Enter first test item's barcode + 43 | await scanInput.fill(TEST_ITEMS[0].barcode); + 44 | await scanInput.press('Enter'); + 45 | + 46 | // Should show stock adjustment form + 47 | await assertions.assertStockAdjustmentVisible(page, TEST_ITEMS[0].name); + 48 | + 49 | // Verify item details are shown + 50 | const itemName = page.locator('[data-testid="adjustment-item-name"]'); + 51 | await expect(itemName).toContainText(TEST_ITEMS[0].name); + 52 | }); + 53 | + 54 | test('should default to check-in operation', async ({ page }) => { + 55 | const scanInput = page.locator('[data-testid="scan-input"]'); + 56 | await scanInput.fill(TEST_ITEMS[0].barcode); + 57 | await scanInput.press('Enter'); + 58 | + 59 | // Check-in radio should be selected + 60 | const checkInRadio = page.locator('[data-testid="operation-checkin"]'); + 61 | await expect(checkInRadio).toBeChecked(); + 62 | }); + 63 | + 64 | test('should allow switching between check-in and check-out', async ({ page }) => { + 65 | const scanInput = page.locator('[data-testid="scan-input"]'); + 66 | await scanInput.fill(TEST_ITEMS[0].barcode); + 67 | await scanInput.press('Enter'); + 68 | + 69 | // Switch to check-out + 70 | const checkOutRadio = page.locator('[data-testid="operation-checkout"]'); + 71 | await checkOutRadio.click(); + 72 | await expect(checkOutRadio).toBeChecked(); + 73 | + 74 | // Switch back to check-in + 75 | const checkInRadio = page.locator('[data-testid="operation-checkin"]'); + 76 | await checkInRadio.click(); + 77 | await expect(checkInRadio).toBeChecked(); + 78 | }); + 79 | + 80 | test('should allow quantity adjustment', async ({ page }) => { + 81 | const scanInput = page.locator('[data-testid="scan-input"]'); + 82 | await scanInput.fill(TEST_ITEMS[0].barcode); + 83 | await scanInput.press('Enter'); + 84 | + 85 | // Change quantity + 86 | const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); + 87 | await quantityInput.fill('10'); + 88 | + 89 | // Verify value changed + 90 | const value = await helpers.getInputValue(page, '[data-testid="adjustment-quantity-input"]'); + 91 | expect(value).toBe('10'); + 92 | }); + 93 | + 94 | test('should reject invalid quantities', async ({ page }) => { + 95 | const scanInput = page.locator('[data-testid="scan-input"]'); + 96 | await scanInput.fill(TEST_ITEMS[0].barcode); + 97 | await scanInput.press('Enter'); + 98 | + 99 | // Try invalid quantity + 100 | const quantityInput = page.locator('[data-testid="adjustment-quantity-input"]'); + 101 | await quantityInput.fill('-5'); + 102 | + 103 | // Submit should be disabled or show error + 104 | const submitButton = page.locator('[data-testid="adjustment-submit"]'); + 105 | if (await submitButton.isEnabled()) { + 106 | await submitButton.click(); + 107 | const errorToast = page.locator('[data-testid="toast-error"]'); + 108 | await expect(errorToast).toBeVisible({ timeout: 3000 }); + 109 | } + 110 | }); + 111 | + 112 | test('should submit stock adjustment successfully', async ({ page }) => { +``` \ No newline at end of file diff --git a/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/test-failed-1.png b/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/test-failed-1.png new file mode 100644 index 00000000..3ddab50b Binary files /dev/null and b/frontend/test-results/2-scan-adjust-Scan-and-Adj-ce512--interface-with-camera-view-chromium/test-failed-1.png differ