- Add connected-path tests for mysql, sql-server, and postgresql using mocked drivers (mysql2/promise, mssql, pg) covering connect, query, transaction, and disconnect scenarios - Fix tautological assertion in auth-flow.test.ts (hasError >= 0 was always true) - Add tests/integration to vitest exclude list to prevent module cache pollution under isolate:false - Set isolate to true for CI, false for local dev (was: isolate false)
95 lines
3.3 KiB
TypeScript
95 lines
3.3 KiB
TypeScript
/**
|
|
* E2E Tests for Authentication Flow
|
|
*
|
|
* Tests the complete authentication workflow including:
|
|
* - Silent login
|
|
* - Manual login
|
|
* - Logout
|
|
* - Session management
|
|
*/
|
|
|
|
import { test, expect, ElectronApplication, Page } from '@playwright/test'
|
|
import { _electron as electron } from 'playwright'
|
|
import path from 'path'
|
|
|
|
let electronApp: ElectronApplication
|
|
let page: Page
|
|
|
|
test.describe('Authentication Flow', () => {
|
|
test.beforeAll(async () => {
|
|
// Launch Electron app
|
|
electronApp = await electron.launch({
|
|
args: [path.join(__dirname, '../../out/main/index.js')],
|
|
env: {
|
|
NODE_ENV: 'test'
|
|
}
|
|
})
|
|
|
|
// Get the first window
|
|
page = await electronApp.firstWindow()
|
|
|
|
// Wait for app to load
|
|
await page.waitForLoadState('domcontentloaded')
|
|
})
|
|
|
|
test.afterAll(async () => {
|
|
await electronApp.close()
|
|
})
|
|
|
|
test('should show login dialog on first load', async () => {
|
|
// Check if login dialog or main content is visible
|
|
const loginDialog = page.locator('[data-testid="login-dialog"]')
|
|
const mainContent = page.locator('[data-testid="main-content"]')
|
|
|
|
// Either login dialog or main content should be visible
|
|
const isLoginVisible = await loginDialog.isVisible().catch(() => false)
|
|
const isMainVisible = await mainContent.isVisible().catch(() => false)
|
|
|
|
expect(isLoginVisible || isMainVisible).toBe(true)
|
|
})
|
|
|
|
test('should have login form elements', async () => {
|
|
// Check for login form elements if login dialog is visible
|
|
const usernameInput = page.locator('input[type="text"], input[name="username"]')
|
|
const passwordInput = page.locator('input[type="password"], input[name="password"]')
|
|
const loginButton = page.locator('button:has-text("登录"), button:has-text("Login")')
|
|
|
|
// Check if at least one of each exists
|
|
const hasUsername = await usernameInput.count()
|
|
const hasPassword = await passwordInput.count()
|
|
const hasLoginButton = await loginButton.count()
|
|
|
|
// If login dialog is shown, these elements should exist
|
|
if (hasUsername > 0 || hasPassword > 0) {
|
|
expect(hasUsername).toBeGreaterThan(0)
|
|
expect(hasPassword).toBeGreaterThan(0)
|
|
expect(hasLoginButton).toBeGreaterThan(0)
|
|
}
|
|
})
|
|
|
|
test('should show error on invalid credentials', async () => {
|
|
const usernameInput = page.locator('input[type="text"], input[name="username"]').first()
|
|
const passwordInput = page.locator('input[type="password"], input[name="password"]').first()
|
|
const loginButton = page.locator('button:has-text("登录"), button:has-text("Login")').first()
|
|
|
|
// Only test if login form is visible
|
|
if (await usernameInput.isVisible().catch(() => false)) {
|
|
await usernameInput.fill('invalid_user')
|
|
await passwordInput.fill('invalid_password')
|
|
await loginButton.click()
|
|
|
|
// Wait for error message
|
|
await page.waitForTimeout(1000)
|
|
|
|
// Check for error message
|
|
const errorMessage = page.locator('.error, [role="alert"], .text-red')
|
|
const hasError = await errorMessage.count()
|
|
|
|
// Verify login was rejected: either error shown or still on login page
|
|
const loginDialog = page.locator('[data-testid="login-dialog"]')
|
|
const isStillOnLoginPage = await loginDialog.isVisible().catch(() => false)
|
|
expect(hasError > 0 || isStillOnLoginPage).toBe(true)
|
|
}
|
|
})
|
|
})
|