dy-dashboard/tests/test_user_import_csv.py
2026-10-28 11:14:17 +08:00

110 lines
4.4 KiB
Python

"""用户批量导入 CSV / XLSX / XLS 回归测试。"""
import io
import unittest
from pathlib import Path
from unittest.mock import patch
from openpyxl import Workbook
from routes.users import (
_normalize_department,
_parse_user_import_csv,
_parse_user_import_file,
_parse_user_import_xls,
)
ROOT = Path(__file__).resolve().parents[1]
APP_JS = (ROOT / 'static' / 'js' / 'app.js').read_text(encoding='utf-8')
HEADERS = ['用户名', '密码', '真实姓名', '角色', '员工级别', '岗位', '手机', '邮箱', '状态']
class UserImportFileTest(unittest.TestCase):
def test_accepts_excel_style_cr_line_endings(self):
content = (
'用户名,密码,真实姓名,角色,员工级别,岗位,手机,邮箱,状态\r'
'zhangsan,Abc123!@#45,张三,viewer,employee,采购专员,,,1\r'
)
rows = _parse_user_import_csv(content.encode('utf-8-sig'))
self.assertEqual(1, len(rows))
self.assertEqual('zhangsan', rows[0]['用户名'])
self.assertEqual('Abc123!@#45', rows[0]['密码'])
def test_accepts_crlf_and_gbk(self):
content = (
'用户名,密码,真实姓名,角色,员工级别,岗位,部门,手机,邮箱,状态\r\n'
'lisi,Xyz789$%^01,李四,viewer,employee,仓库专员,天猫,,,1\r\n'
)
rows = _parse_user_import_file(content.encode('gbk'), '用户列表.CSV')
self.assertEqual('李四', rows[0]['真实姓名'])
self.assertEqual('天猫', rows[0]['部门'])
def test_department_options_accept_blank_and_reject_unknown(self):
self.assertEqual('', _normalize_department(''))
for department in ('天猫', '京东', '天猫国际', '京东国际', '阿里', '新媒体', '拼多多', 'AI指挥部', '采购部', '产品部'):
self.assertEqual(department, _normalize_department(department))
with self.assertRaisesRegex(ValueError, '部门必须为'):
_normalize_department('其他部门')
def test_accepts_xlsx_and_preserves_integer_phone(self):
workbook = Workbook()
sheet = workbook.active
sheet.append(HEADERS)
sheet.append(['wangwu', 'Safe123!@#45', '王五', 'viewer', 'employee', '仓库专员', 13800138000, '', 1])
output = io.BytesIO()
workbook.save(output)
workbook.close()
rows = _parse_user_import_file(output.getvalue(), '用户列表.xlsx')
self.assertEqual(1, len(rows))
self.assertEqual('wangwu', rows[0]['用户名'])
self.assertEqual('13800138000', rows[0]['手机'])
self.assertEqual('1', rows[0]['状态'])
def test_accepts_xls_first_sheet(self):
class FakeSheet:
nrows = 2
def row_values(self, index):
return HEADERS if index == 0 else [
'zhaoliu', 'Strong123!@#', '赵六', 'viewer', 'employee', '采购专员', 13900139000.0, '', 1.0
]
class FakeBook:
nsheets = 1
def sheet_by_index(self, index):
self.requested_index = index
return FakeSheet()
with patch('xlrd.open_workbook', return_value=FakeBook()) as open_workbook:
rows = _parse_user_import_xls(b'fake-xls')
open_workbook.assert_called_once_with(file_contents=b'fake-xls')
self.assertEqual('zhaoliu', rows[0]['用户名'])
self.assertEqual('13900139000', rows[0]['手机'])
def test_rejects_wrong_template_headers(self):
with self.assertRaisesRegex(ValueError, '表头'):
_parse_user_import_csv('账号,口令\na,b\n'.encode('utf-8'))
def test_reports_malformed_csv_without_partial_iteration(self):
malformed = '用户名,密码\n"zhangsan,Abc123!@#45\n'.encode('utf-8')
with self.assertRaisesRegex(ValueError, 'CSV格式错误'):
_parse_user_import_csv(malformed)
def test_rejects_unsupported_extension(self):
with self.assertRaisesRegex(ValueError, '仅支持CSV、XLSX、XLS'):
_parse_user_import_file(b'content', 'users.txt')
def test_frontend_accepts_all_three_formats(self):
self.assertIn('accept=".csv,.xlsx,.xls"', APP_JS)
self.assertIn("['csv', 'xlsx', 'xls'].includes(extension)", APP_JS)
self.assertIn('file_base64: result.slice(commaIndex + 1)', APP_JS)
self.assertIn('id="userDepartmentFilter"', APP_JS)
self.assertIn('id="editDepartment"', APP_JS)
if __name__ == '__main__':
unittest.main()