Files
BIPMaterialManager/tests/unit/services/erp/erp-auth.test.ts
Misaka d0f8ad0fef test(erp): add unit tests for ERP services and test coverage docs
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>
2026-04-05 17:23:00 +08:00

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)
})
})
})