Files
craft-libs/crates/ui/tests/screens.rs
T
aiongg 3c574ddc61 craft-ui: interface fonts, text direction, IME composer, localized widgets and screen testing
craft-fonts-build gains Embed::serve (served faces for web builds) and the coverage module that craft-ui's fonts use.
2026-10-25 19:08:59 +00:00

99 lines
4.0 KiB
Rust

//! A rename dialog in the six test languages: the example of `craft_ui::testing` for app tests.
//!
//! The snapshots are in `tests/snapshots/rename-*.png`; `UPDATE_SNAPSHOTS=1` rewrites them.
use craft_ui::fonts::CraftFace;
use craft_ui::testing::{JAPANESE, KOREAN, Locale, Screens, compose};
use egui::accesskit::Role;
use egui::{FontData, FontFamily, Ui};
use egui_kittest::kittest::Queryable as _;
const ARABIC: CraftFace = CraftFace {
family: "Noto Sans Arabic",
style: "Regular",
scripts: &["Arab"],
bytes: include_bytes!("fonts/NotoSansArabic-screens.ttf"),
index: 0,
};
// The subset has the dialog's kana, Han and Hangul, so it stands in for every CJK face. Its Latin
// glyphs, Vietnamese included, are the app's UI face: egui's default face has no Vietnamese.
const CJK: CraftFace = CraftFace {
family: "Noto Sans CJK SC",
style: "Regular",
scripts: &["Jpan", "Kore", "Hans", "Hant"],
bytes: include_bytes!("fonts/NotoSansCJKsc-screens.otf"),
index: 0,
};
const THAI: CraftFace =
CraftFace { family: "Noto Sans Thai", style: "Regular", scripts: &["Thai"], bytes: include_bytes!("fonts/NotoSansThai-screens.ttf"), index: 0 };
struct Strings {
title: &'static str,
name: &'static str,
file: &'static str,
keep: &'static str,
cancel: &'static str,
rename: &'static str,
}
fn strings(language: &str) -> Strings {
let [title, name, file, keep, cancel, rename] = match language {
"ar" => ["إعادة تسمية الملف", "الاسم", "تقرير ٢٠٢٦.pdf", "الإبقاء على الامتداد", "إلغاء", "إعادة التسمية"],
"ja" => ["ファイル名を変更", "名前", "報告書 2026.pdf", "拡張子を保持", "キャンセル", "変更"],
"zh-TW" => ["重新命名檔案", "名稱", "報告 2026.pdf", "保留副檔名", "取消", "重新命名"],
"ko" => ["파일 이름 바꾸기", "이름", "보고서 2026.pdf", "확장자 유지", "취소", "이름 바꾸기"],
"th" => ["เปลี่ยนชื่อไฟล์", "ชื่อ", "รายงาน 2026.pdf", "เก็บนามสกุลไฟล์", "ยกเลิก", "เปลี่ยนชื่อ"],
"vi" => ["Đổi tên tệp", "Tên", "Báo cáo 2026.pdf", "Giữ phần mở rộng", "Hủy", "Đổi tên"],
_ => ["Rename file", "Name", "Report 2026.pdf", "Keep extension", "Cancel", "Rename"],
};
Strings { title, name, file, keep, cancel, rename }
}
struct Dialog {
file: String,
keep: bool,
}
impl Dialog {
fn new(locale: &Locale) -> Self {
Self { file: strings(locale.language).file.to_owned(), keep: true }
}
fn ui(&mut self, ui: &mut Ui, locale: &Locale) {
let text = strings(locale.language);
ui.heading(text.title);
ui.horizontal(|ui| {
let label = ui.label(text.name);
ui.text_edit_singleline(&mut self.file).labelled_by(label.id);
});
ui.checkbox(&mut self.keep, text.keep);
ui.horizontal(|ui| {
_ = ui.button(text.rename);
_ = ui.button(text.cancel);
});
}
}
fn screens() -> Screens {
Screens::new("rename")
.size([320.0, 150.0])
.fonts(|fonts| fonts.app_face("ui", FontData::from_static(CJK.bytes), &[FontFamily::Proportional]).craft_faces(&[ARABIC, CJK, THAI]))
}
#[test]
fn testing_rename_dialog_snapshots() {
screens().snapshots(|ui, locale| Dialog::new(locale).ui(ui, locale));
}
#[test]
fn testing_rename_dialog_takes_ime_input() {
for (language, composition) in [("ko", KOREAN), ("ja", JAPANESE)] {
let dialog = Dialog { file: String::new(), keep: true };
let mut harness = screens().harness_state(language, |ui, locale, dialog: &mut Dialog| dialog.ui(ui, locale), dialog);
harness.get_by_role(Role::TextInput).focus();
harness.run();
compose(&mut harness, &composition);
assert_eq!(harness.state().file, composition.commit, "{language}");
}
}