You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
szkp-map-service/tests/Unit/StudyTourDeclarationExporte...

128 lines
4.8 KiB

2 days ago
<?php
namespace Tests\Unit;
use App\Support\StudyTourDeclarationExporter;
use PhpOffice\PhpWord\IOFactory;
use Tests\TestCase;
use ZipArchive;
class StudyTourDeclarationExporterTest extends TestCase
{
public function test_html_to_plain_text_keeps_paragraphs(): void
{
$html = '<p>第一段</p><p>第二段<br/>续行</p><ul><li>要点A</li><li>要点B</li></ul>';
$text = StudyTourDeclarationExporter::htmlToPlainText($html);
$this->assertStringContainsString("第一段", $text);
$this->assertStringContainsString("第二段", $text);
$this->assertStringContainsString("续行", $text);
$this->assertStringContainsString("要点A", $text);
$this->assertStringContainsString("要点B", $text);
}
public function test_sanitize_filename_strips_illegal_chars(): void
{
$this->assertSame('线路A_B', StudyTourDeclarationExporter::sanitizeFilename('线路A/B'));
$this->assertSame('研学线路', StudyTourDeclarationExporter::sanitizeFilename(' '));
}
public function test_docx_contains_declaration_sections_and_cover_image(): void
{
$png = sys_get_temp_dir().'/st-cover-test.png';
file_put_contents($png, base64_decode(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='
));
2 days ago
$uploadDir = storage_path('app/public/uploads');
if (! is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$implPng = $uploadDir.'/st-impl-test.png';
copy($png, $implPng);
2 days ago
$path = StudyTourDeclarationExporter::writeDocxFile([
'name' => '太湖蚕桑研学',
'org_name' => '苏州市科协',
'seasons' => ['spring', 'autumn'],
'venue_names' => ['苏州丝绸博物馆', '自定义营地'],
'suitable_count' => '30人',
'suitable_audience' => 'primaryjunior',
'duration' => '2天1晚',
'contact_person' => '张老师',
'contact_phones' => '13800000000',
'cover_image_path' => $png,
'intro_html' => '<p>走进蚕桑文化。</p>',
'route_plans' => [[
'date_label' => '第一天',
'items' => [[
'time' => '09:00',
'activity' => '开营仪式',
'location' => '活动中心',
]],
]],
'courses' => [[
'sort' => 1,
'name' => '缫丝体验',
'content' => '了解传统缫丝工艺',
]],
'fee_html' => '<p>680元/人</p>',
2 days ago
'implementation_html' => '<p>2026年7月1日第1场</p><p><img src="/storage/uploads/st-impl-test.png"></p>',
2 days ago
'season_options' => [
['value' => 'spring', 'label' => '春季'],
['value' => 'summer', 'label' => '夏季'],
['value' => 'autumn', 'label' => '秋季'],
['value' => 'winter', 'label' => '冬季'],
],
'audience_options' => [
['value' => 'kindergarten', 'label' => '幼儿园'],
['value' => 'primary', 'label' => '小学'],
['value' => 'junior', 'label' => '初中'],
['value' => 'high', 'label' => '高中'],
['value' => 'all', 'label' => '全学段'],
],
]);
$this->assertFileExists($path);
$zip = new ZipArchive();
$this->assertTrue($zip->open($path) === true);
$xml = (string) $zip->getFromName('word/document.xml');
$mediaCount = 0;
for ($i = 0; $i < $zip->numFiles; $i++) {
$name = (string) $zip->getNameIndex($i);
if (str_starts_with($name, 'word/media/')) {
$mediaCount++;
}
}
$zip->close();
foreach ([
'一、线路基本情况',
'二、线路简介',
'三、线路规划',
'四、研学课程',
'五、线路收费标准',
'六、线路计划实施情况',
'太湖蚕桑研学',
'苏州市科协',
'苏州丝绸博物馆',
'走进蚕桑文化',
'开营仪式',
'缫丝体验',
'680元/人',
'封面图',
2 days ago
'2026年7月1日第1场',
2 days ago
] as $needle) {
$this->assertStringContainsString($needle, $xml, "missing {$needle}");
}
2 days ago
$this->assertGreaterThanOrEqual(2, $mediaCount, 'cover and implementation images should be embedded');
2 days ago
$phpWord = IOFactory::load($path);
$this->assertNotEmpty($phpWord->getSections());
@unlink($path);
@unlink($png);
2 days ago
@unlink($implPng);
2 days ago
}
}