Add unit tests for core ERP service modules including ErpBrowserManager, cleaner, erp-auth, extractor-core, extractor, and order-resolver. Also includes test coverage improvement plan and quality review report. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
217 lines
6.0 KiB
TypeScript
217 lines
6.0 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { chromium } from 'playwright'
|
|
import { ErpAuthService } from '@main/services/erp/erp-auth'
|
|
import type { ErpConfig } from '@main/types/erp.types'
|
|
|
|
// Mock logger
|
|
vi.mock('@main/services/logger', () => ({
|
|
createLogger: vi.fn(() => ({
|
|
info: vi.fn(),
|
|
debug: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn()
|
|
}))
|
|
}))
|
|
|
|
// Mock playwright
|
|
vi.mock('playwright', () => ({
|
|
chromium: {
|
|
launch: vi.fn()
|
|
}
|
|
}))
|
|
|
|
vi.mock('@main/services/erp/erp-error-context', () => ({
|
|
capturePageContext: vi.fn().mockResolvedValue({})
|
|
}))
|
|
|
|
vi.mock('@main/services/erp/page-diagnostics', () => ({
|
|
attachPageDiagnostics: vi.fn(),
|
|
attachContextDiagnostics: vi.fn()
|
|
}))
|
|
|
|
describe('ErpAuthService', () => {
|
|
let config: ErpConfig
|
|
let service: ErpAuthService
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
config = {
|
|
url: 'https://test-erp.com',
|
|
username: 'testuser',
|
|
password: 'testpass',
|
|
headless: true
|
|
}
|
|
})
|
|
|
|
describe('constructor()', () => {
|
|
it('should store config', () => {
|
|
service = new ErpAuthService(config)
|
|
|
|
// Verify config is stored by checking isActive returns false (default state)
|
|
expect(service.isActive()).toBe(false)
|
|
})
|
|
|
|
it('should initialize with null session', () => {
|
|
service = new ErpAuthService(config)
|
|
|
|
expect(service.isActive()).toBe(false)
|
|
expect(() => service.getSession()).toThrow('Not logged in')
|
|
})
|
|
})
|
|
|
|
describe('getSession()', () => {
|
|
beforeEach(() => {
|
|
service = new ErpAuthService(config)
|
|
})
|
|
|
|
it('should throw error when not logged in', () => {
|
|
expect(() => service.getSession()).toThrow('Not logged in. Call login() first.')
|
|
})
|
|
|
|
it('should return session when logged in', () => {
|
|
// Manually set session state (bypassing login for unit test)
|
|
;(service as any).session = {
|
|
browser: {},
|
|
context: {},
|
|
page: {},
|
|
mainFrame: {},
|
|
isLoggedIn: true
|
|
}
|
|
|
|
const session = service.getSession()
|
|
|
|
expect(session).toBeDefined()
|
|
expect(session.isLoggedIn).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('isActive()', () => {
|
|
beforeEach(() => {
|
|
service = new ErpAuthService(config)
|
|
})
|
|
|
|
it('should return false when not logged in', () => {
|
|
expect(service.isActive()).toBe(false)
|
|
})
|
|
|
|
it('should return true when logged in', () => {
|
|
// Manually set session state (bypassing login for unit test)
|
|
;(service as any).session = {
|
|
browser: {},
|
|
context: {},
|
|
page: {},
|
|
mainFrame: {},
|
|
isLoggedIn: true
|
|
}
|
|
|
|
expect(service.isActive()).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('login()', () => {
|
|
let mockBrowser: any
|
|
let mockContext: any
|
|
let mockPage: any
|
|
let mockFrame: any
|
|
|
|
beforeEach(() => {
|
|
mockFrame = {
|
|
locator: vi.fn().mockReturnThis(),
|
|
getByRole: vi.fn().mockReturnValue({
|
|
fill: vi.fn().mockResolvedValue(undefined),
|
|
click: vi.fn().mockResolvedValue(undefined)
|
|
}),
|
|
getByText: vi.fn().mockReturnValue({
|
|
waitFor: vi.fn().mockResolvedValue(undefined),
|
|
isVisible: vi.fn().mockResolvedValue(false)
|
|
}),
|
|
waitFor: vi.fn().mockResolvedValue(undefined)
|
|
}
|
|
|
|
mockPage = {
|
|
goto: vi.fn().mockResolvedValue(undefined),
|
|
waitForLoadState: vi.fn().mockResolvedValue(undefined),
|
|
waitForSelector: vi.fn().mockResolvedValue(undefined),
|
|
locator: vi.fn().mockReturnValue({
|
|
contentFrame: vi.fn().mockResolvedValue(mockFrame)
|
|
})
|
|
}
|
|
|
|
mockContext = {
|
|
newPage: vi.fn().mockResolvedValue(mockPage),
|
|
close: vi.fn().mockResolvedValue(undefined)
|
|
}
|
|
|
|
mockBrowser = {
|
|
newContext: vi.fn().mockResolvedValue(mockContext),
|
|
close: vi.fn().mockResolvedValue(undefined)
|
|
}
|
|
|
|
vi.mocked(chromium.launch).mockResolvedValue(mockBrowser as any)
|
|
})
|
|
|
|
it('should create session on successful login', async () => {
|
|
service = new ErpAuthService(config)
|
|
|
|
const session = await service.login()
|
|
|
|
expect(chromium.launch).toHaveBeenCalledWith(expect.objectContaining({ headless: true }))
|
|
expect(mockBrowser.newContext).toHaveBeenCalled()
|
|
expect(mockContext.newPage).toHaveBeenCalled()
|
|
expect(session.isLoggedIn).toBe(true)
|
|
expect(session.browser).toBe(mockBrowser)
|
|
expect(session.context).toBe(mockContext)
|
|
expect(session.page).toBe(mockPage)
|
|
expect(session.mainFrame).toBe(mockFrame)
|
|
})
|
|
|
|
it('should reuse existing session if already logged in', async () => {
|
|
service = new ErpAuthService(config)
|
|
const firstSession = await service.login()
|
|
|
|
// Second call should return same session
|
|
const secondSession = await service.login()
|
|
|
|
expect(secondSession).toBe(firstSession)
|
|
expect(chromium.launch).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('should throw when forwardFrame contentFrame returns null', async () => {
|
|
service = new ErpAuthService(config)
|
|
mockPage.locator = vi.fn().mockReturnValue({
|
|
contentFrame: vi.fn().mockResolvedValue(null)
|
|
})
|
|
|
|
await expect(service.login()).rejects.toThrow('Failed to access forwardFrame content frame')
|
|
})
|
|
})
|
|
|
|
describe('close()', () => {
|
|
beforeEach(() => {
|
|
service = new ErpAuthService(config)
|
|
})
|
|
|
|
it('should be no-op when not logged in', async () => {
|
|
// Should not throw when calling close without session
|
|
await expect(service.close()).resolves.not.toThrow()
|
|
expect(service.isActive()).toBe(false)
|
|
})
|
|
|
|
it('should clear session when logged in', async () => {
|
|
// Manually set session state
|
|
const mockSession = {
|
|
browser: { close: vi.fn().mockResolvedValue(undefined) },
|
|
context: { close: vi.fn().mockResolvedValue(undefined) },
|
|
page: {},
|
|
mainFrame: {},
|
|
isLoggedIn: true
|
|
}
|
|
;(service as any).session = mockSession
|
|
|
|
await service.close()
|
|
|
|
expect(service.isActive()).toBe(false)
|
|
})
|
|
})
|
|
})
|