dootask/tests/Unit/UserImportParseTest.php
kuaifan 20b5daba50 feat(manage): 团队管理支持管理员创建/批量导入员工账号(含部门、职位)
单个创建:邮箱/昵称/初始密码 + 可选首登改密、职位、部门(多选,选子部门自动补选上级,并加入对应部门群)。

批量导入:上传 Excel/CSV → 预览逐行校验 → 确认后导入。职位为模板第4列(选填,逐行解析校验),部门在预览表按行勾选后由底部设置部门到选中写入;导入按行返回结果(全成功关弹窗+成功提示;含失败留弹窗显示失败明细;仅 success>0 才刷新列表)。

后端:User::createByAdmin 选项数组化 + 校验助手 assertValidProfession/assertValidDepartments;importUsers 逐行 department/profession;UsersController createuser/import;UserImport/UserImportTemplate(含职位列)。

测试:tests/Feature/AdminCreateUserTest、tests/Unit/UserImportParseTest。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 01:26:34 +00:00

138 lines
5.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Tests\Unit;
use App\Models\User;
use Tests\TestCase;
class UserImportParseTest extends TestCase
{
public function test_parse_skips_header_and_empty_rows()
{
$sheet = [
['邮箱', '昵称', '初始密码'], // 表头,应跳过
['a@test.local', '张三', 'Abc123456'],
['', '', ''], // 空行,应跳过
['b@test.local', '李四', 'Xyz123456'],
];
$rows = User::parseImportRows($sheet);
$this->assertCount(2, $rows);
$this->assertSame('a@test.local', $rows[0]['email']);
$this->assertSame('张三', $rows[0]['nickname']);
$this->assertSame('Abc123456', $rows[0]['password']);
$this->assertSame(2, $rows[0]['line']);
$this->assertSame(4, $rows[1]['line']);
}
public function test_parse_trims_cells()
{
$sheet = [
['邮箱', '昵称', '初始密码'],
[' a@test.local ', ' 张三 ', ' Abc123456 '],
];
$rows = User::parseImportRows($sheet);
$this->assertSame('a@test.local', $rows[0]['email']);
$this->assertSame('张三', $rows[0]['nickname']);
$this->assertSame('Abc123456', $rows[0]['password']);
}
public function test_validate_passes_for_valid_row()
{
$row = ['email' => 'ok@test.local', 'nickname' => '张三', 'password' => 'Abc123456'];
$this->assertNull(User::validateImportRow($row));
}
public function test_validate_requires_all_fields()
{
$this->assertSame('邮箱、昵称、初始密码均为必填', User::validateImportRow(['email' => '', 'nickname' => '张三', 'password' => 'Abc123456']));
$this->assertSame('邮箱、昵称、初始密码均为必填', User::validateImportRow(['email' => 'a@test.local', 'nickname' => '', 'password' => 'Abc123456']));
$this->assertSame('邮箱、昵称、初始密码均为必填', User::validateImportRow(['email' => 'a@test.local', 'nickname' => '张三', 'password' => '']));
}
public function test_validate_rejects_bad_email()
{
$this->assertSame('邮箱格式不正确', User::validateImportRow(['email' => 'not-an-email', 'nickname' => '张三', 'password' => 'Abc123456']));
}
public function test_validate_rejects_bad_nickname_length()
{
$this->assertSame('昵称需为2-20个字', User::validateImportRow(['email' => 'a@test.local', 'nickname' => '王', 'password' => 'Abc123456']));
$this->assertSame('昵称需为2-20个字', User::validateImportRow(['email' => 'a@test.local', 'nickname' => str_repeat('字', 21), 'password' => 'Abc123456']));
}
public function test_validate_rejects_short_password()
{
$this->assertNotNull(User::validateImportRow(['email' => 'a@test.local', 'nickname' => '张三', 'password' => '123']));
}
public function test_assert_valid_profession_passes_for_empty_and_normal()
{
// 空职位允许可选字段2/20 字边界与正常值允许;不抛异常即通过
User::assertValidProfession('');
User::assertValidProfession('工程'); // 恰好 2 字
User::assertValidProfession('工程师');
User::assertValidProfession(str_repeat('字', 20)); // 恰好 20 字
$this->assertTrue(true);
}
public function test_assert_valid_profession_rejects_too_short()
{
$this->expectException(\App\Exceptions\ApiException::class);
$this->expectExceptionMessage('职位/职称不可以少于2个字');
User::assertValidProfession('A');
}
public function test_assert_valid_profession_rejects_too_long()
{
$this->expectException(\App\Exceptions\ApiException::class);
$this->expectExceptionMessage('职位/职称最多只能设置20个字');
User::assertValidProfession(str_repeat('字', 21));
}
public function test_assert_valid_departments_normalizes_ids()
{
// 空/非数组 → 返回空数组
$this->assertSame([], User::assertValidDepartments([]));
$this->assertSame([], User::assertValidDepartments('not-array'));
// 去重 + 转 int + 过滤非正数(这些路径不查库)
$this->assertSame([3, 5], User::assertValidDepartments(['3', 3, 5, 0, -1]));
}
public function test_assert_valid_departments_rejects_over_limit()
{
// 超过 10 个count 校验在查库之前)→ 抛异常
$this->expectException(\App\Exceptions\ApiException::class);
$this->expectExceptionMessage('最多只可加入10个部门');
User::assertValidDepartments(range(1, 11));
}
public function test_parse_reads_profession_column()
{
$sheet = [
['邮箱', '昵称', '初始密码', '职位'],
['a@test.local', '张三', 'Abc123456', '工程师'],
['b@test.local', '李四', 'Xyz123456'], // 无职位列 → profession 为空
];
$rows = User::parseImportRows($sheet);
$this->assertCount(2, $rows);
$this->assertSame('工程师', $rows[0]['profession']);
$this->assertSame('', $rows[1]['profession']);
}
public function test_validate_passes_for_empty_profession()
{
$row = ['email' => 'a@test.local', 'nickname' => '张三', 'password' => 'Abc123456', 'profession' => ''];
$this->assertNull(User::validateImportRow($row));
}
public function test_validate_rejects_bad_profession()
{
$row = ['email' => 'a@test.local', 'nickname' => '张三', 'password' => 'Abc123456', 'profession' => 'A'];
$this->assertSame('职位/职称不可以少于2个字', User::validateImportRow($row));
}
}