Files
ECShopX/tests/MenuImportTest.php
2026-03-27 18:01:17 +08:00

286 lines
12 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
/**
* 菜单导入多语言与兼容测试
* 计划:.tasks/plans/menu-multilang-export-import.md TODO 5RED、TODO 6/7GREEN
* 用例TC-I1TC-I6新格式主表+多语言、旧格式仅主表、重复导入无残留、部分语种、空 name_lang、单条部分语种
* 当前仅编写测试,不实现多语言写入/删除。
* RED 证据(需 DB 可用时TC-I1/I3/I4/I6 会因多语言表无数据或未先 deleteLang 而断言失败TC-I2/I5 可能已绿(仅主表、不写多语言)。
*/
use CompanysBundle\Services\CommonLangModService;
use SuperAdminBundle\Services\ShopMenuService;
class MenuImportTest extends TestCase
{
/** @var string[] config 语种,与 config/langue.php 一致 */
private const CONFIG_LANGS = ['zh-CN', 'en-CN', 'ar-SA'];
/**
* 构造一条可供 uploadMenus 使用的最小合法菜单行(可含 name_lang
*/
private function buildUploadMenuRow(array $overrides = []): array
{
$defaults = [
'shopmenu_id' => 1,
'version' => 1,
'company_id' => 0,
'alias_name' => 'import_test_' . uniqid(),
'name' => 'Test Menu',
'url' => '/test',
'sort' => 1,
'pid' => 0,
'apis' => '',
'icon' => '',
'is_show' => true,
'is_menu' => true,
'disabled' => false,
'menu_type' => ['all'],
];
return array_merge($defaults, $overrides);
}
/**
* 导入后按 version+company_id 取第一条菜单的 shopmenu_id用于单条断言
*/
private function getFirstInsertedShopmenuId(ShopMenuService $service, int $version, int $companyId): ?int
{
$res = $service->shopMenuRepository->lists(
['version' => $version, 'company_id' => $companyId],
'shopmenu_id',
1,
1,
['shopmenu_id' => 'ASC']
);
$list = $res['list'] ?? [];
return isset($list[0]['shopmenu_id']) ? (int) $list[0]['shopmenu_id'] : null;
}
/**
* 按 alias_name 查找导入后的 shopmenu_id
*/
private function getShopmenuIdByAlias(ShopMenuService $service, int $version, int $companyId, string $aliasName): ?int
{
$res = $service->shopMenuRepository->getInfo([
'version' => $version,
'company_id' => $companyId,
'alias_name' => $aliasName,
]);
return isset($res['shopmenu_id']) ? (int) $res['shopmenu_id'] : null;
}
/**
* TC-I1新格式文件含 3 语种 name_lang。
* #given 新格式 list 含 name 与 name_lang(zh-CN, en-CN, ar-SA)
* #when 调用 uploadMenus 导入
* #then 主表 name 正确3 个多语言表均有对应 data_id 的 attribute_value当前 RED未实现 saveLang
*/
public function testImportNewFormatWithThreeLanguagesWritesMainTableAndMultilangTcI1(): void
{
$companyId = 0;
$version = 91; // SMALLINT 范围内,避免与业务 version 1-7 冲突
$row = $this->buildUploadMenuRow([
'version' => $version,
'company_id'=> $companyId,
'name' => '首页',
'name_lang' => [
'zh-CN' => '首页',
'en-CN' => 'Home',
'ar-SA' => 'الرئيسية',
],
]);
$service = new ShopMenuService();
$service->uploadMenus([$row], $companyId);
$sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId);
$this->assertNotNull($sid, '导入后应能查到菜单 (TC-I1)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]);
$this->assertSame('首页', $mainMenu['name'] ?? null, '主表 name 应为 list[].name (TC-I1)');
$commonLang = new CommonLangModService();
foreach (self::CONFIG_LANGS as $lang) {
$value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame($row['name_lang'][$lang], $value, "多语言表 {$lang} 应有对应 data_id 的 attribute_value (TC-I1)");
}
}
/**
* TC-I2旧格式文件无 name_lang
* #given 旧格式 list 仅有 name无 name_lang
* #when 调用 uploadMenus 导入
* #then 导入成功,主表 name 正确,多语言表不写入该批(当前可实现:未写多语言即满足)
*/
public function testImportOldFormatWithoutNameLangWritesOnlyMainTableTcI2(): void
{
$companyId = 0;
$version = 92; // SMALLINT 范围内
$row = $this->buildUploadMenuRow([
'version' => $version,
'company_id'=> $companyId,
'name' => '旧格式菜单',
]);
unset($row['name_lang']);
$service = new ShopMenuService();
$service->uploadMenus([$row], $companyId);
$sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId);
$this->assertNotNull($sid, '导入后应能查到菜单 (TC-I2)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]);
$this->assertSame('旧格式菜单', $mainMenu['name'] ?? null, '主表 name 应与文件中 name 一致 (TC-I2)');
$commonLang = new CommonLangModService();
foreach (self::CONFIG_LANGS as $lang) {
$value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame('', $value, '旧格式导入时多语言表不写入该批 (TC-I2)');
}
}
/**
* TC-I3先导入新格式再导入同 version+company 的另一新格式。
* #given 第一次导入含 name_lang第二次导入同 version+company 不同 name_lang
* #when 第二次导入完成
* #then 无第一次的多语言残留,以第二次文件为准(当前 RED未先 deleteLang 再写)
*/
public function testImportSameVersionCompanyTwiceHasNoResidualMultilangTcI3(): void
{
$companyId = 0;
$version = 93; // SMALLINT 范围内
$alias = 'import_tc3_' . uniqid();
$firstRow = $this->buildUploadMenuRow([
'version' => $version,
'company_id' => $companyId,
'alias_name' => $alias,
'name' => '第一版',
'name_lang' => ['zh-CN' => '第一版', 'en-CN' => 'First', 'ar-SA' => ''],
]);
$secondRow = $this->buildUploadMenuRow([
'version' => $version,
'company_id' => $companyId,
'alias_name' => $alias,
'name' => '第二版',
'name_lang' => ['zh-CN' => '第二版', 'en-CN' => 'Second', 'ar-SA' => ''],
]);
$service = new ShopMenuService();
$service->uploadMenus([$firstRow], $companyId);
$sid = $this->getShopmenuIdByAlias($service, $version, $companyId, $alias);
$this->assertNotNull($sid);
$service->uploadMenus([$secondRow], $companyId);
$sid2 = $this->getShopmenuIdByAlias($service, $version, $companyId, $alias);
$this->assertNotNull($sid2, '第二次导入后应有一条菜单 (TC-I3)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid2]);
$this->assertSame('第二版', $mainMenu['name'] ?? null, '主表以第二次为准 (TC-I3)');
$commonLang = new CommonLangModService();
$zhValue = $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid2, 'shop_menu', 'shop_menu');
$this->assertSame('第二版', $zhValue, '第二次导入后无第一次多语言残留zh-CN 应以第二次文件为准 (TC-I3)');
}
/**
* TC-I4新格式但某条 name_lang 仅含 zh-CN。
* #given list 一项 name_lang 仅含 zh-CN
* #when 调用 uploadMenus 导入
* #then 主表 name 取自 list[].name仅 zh-CN 多语言表有该条en-CN/ar-SA 无该 data_id当前 RED未实现 saveLang
*/
public function testImportNewFormatWithOnlyZhCnInNameLangWritesOnlyZhCnTcI4(): void
{
$companyId = 0;
$version = 94; // SMALLINT 范围内
$row = $this->buildUploadMenuRow([
'version' => $version,
'company_id'=> $companyId,
'name' => '概况',
'name_lang' => ['zh-CN' => '概况'],
]);
$service = new ShopMenuService();
$service->uploadMenus([$row], $companyId);
$sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId);
$this->assertNotNull($sid, '导入后应能查到菜单 (TC-I4)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]);
$this->assertSame('概况', $mainMenu['name'] ?? null, '主表 name 取自 list[].name (TC-I4)');
$commonLang = new CommonLangModService();
$zh = $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame('概况', $zh, '仅 zh-CN 多语言表应有该条 (TC-I4)');
$en = $commonLang->getFieldByLangue($companyId, 'en-CN', 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame('', $en, 'en-CN 无该 data_id (TC-I4)');
$ar = $commonLang->getFieldByLangue($companyId, 'ar-SA', 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame('', $ar, 'ar-SA 无该 data_id (TC-I4)');
}
/**
* TC-I5新格式但 name_lang 为空对象 {}。
* #given list 一项 name_lang 为 {}
* #when 调用 uploadMenus 导入
* #then 主表 name 用 list[].name多语言表不写入该条当前可实现未写即满足
*/
public function testImportNewFormatWithEmptyNameLangObjectWritesOnlyMainTableTcI5(): void
{
$companyId = 0;
$version = 95; // SMALLINT 范围内
$row = $this->buildUploadMenuRow([
'version' => $version,
'company_id'=> $companyId,
'name' => '仅主表名称',
'name_lang' => [],
]);
$service = new ShopMenuService();
$service->uploadMenus([$row], $companyId);
$sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId);
$this->assertNotNull($sid, '导入后应能查到菜单 (TC-I5)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]);
$this->assertSame('仅主表名称', $mainMenu['name'] ?? null, '主表 name 用 list[].name (TC-I5)');
$commonLang = new CommonLangModService();
foreach (self::CONFIG_LANGS as $lang) {
$value = $commonLang->getFieldByLangue($companyId, $lang, 'name', $sid, 'shop_menu', 'shop_menu');
$this->assertSame('', $value, 'name_lang 为空对象时多语言表不写入该条 (TC-I5)');
}
}
/**
* TC-I6单条菜单、name_lang 含部分语种。
* #given 单条 listname_lang 仅含 zh-CN 与 en-CN
* #when 调用 uploadMenus 导入
* #then 仅存在的语种写入多语言表(当前 RED未实现 saveLang
*/
public function testImportSingleMenuWithPartialNameLangWritesOnlyPresentLangsTcI6(): void
{
$companyId = 0;
$version = 96; // SMALLINT 范围内
$row = $this->buildUploadMenuRow([
'version' => $version,
'company_id'=> $companyId,
'name' => '边界单条',
'name_lang' => ['zh-CN' => '边界单条', 'en-CN' => 'Single Partial'],
]);
$service = new ShopMenuService();
$service->uploadMenus([$row], $companyId);
$sid = $this->getFirstInsertedShopmenuId($service, $version, $companyId);
$this->assertNotNull($sid, '导入后应能查到菜单 (TC-I6)');
$mainMenu = $service->shopMenuRepository->getInfo(['shopmenu_id' => $sid]);
$this->assertSame('边界单条', $mainMenu['name'] ?? null, '主表 name 用 list[].name (TC-I6)');
$commonLang = new CommonLangModService();
$this->assertSame('边界单条', $commonLang->getFieldByLangue($companyId, 'zh-CN', 'name', $sid, 'shop_menu', 'shop_menu'), 'zh-CN 应写入 (TC-I6)');
$this->assertSame('Single Partial', $commonLang->getFieldByLangue($companyId, 'en-CN', 'name', $sid, 'shop_menu', 'shop_menu'), 'en-CN 应写入 (TC-I6)');
$this->assertSame('', $commonLang->getFieldByLangue($companyId, 'ar-SA', 'name', $sid, 'shop_menu', 'shop_menu'), 'ar-SA 未提供则不写入 (TC-I6)');
}
}