542 lines
17 KiB
TypeScript
542 lines
17 KiB
TypeScript
|
|
/**
|
||
|
|
* 🧪 타입 안전성 종합 테스트 시나리오
|
||
|
|
*
|
||
|
|
* 화면관리, 제어관리, 테이블 타입관리 시스템의 타입 안전성을 검증합니다.
|
||
|
|
* 실제 사용자 시나리오에서 발생할 수 있는 모든 타입 오류 상황을 테스트합니다.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import {
|
||
|
|
ComponentData,
|
||
|
|
WebType,
|
||
|
|
ButtonActionType,
|
||
|
|
WidgetComponent,
|
||
|
|
ContainerComponent,
|
||
|
|
|
||
|
|
// 타입 가드 함수들
|
||
|
|
isWidgetComponent,
|
||
|
|
isContainerComponent,
|
||
|
|
isWebType,
|
||
|
|
isButtonActionType,
|
||
|
|
|
||
|
|
// 안전한 캐스팅 함수들
|
||
|
|
asWidgetComponent,
|
||
|
|
asContainerComponent,
|
||
|
|
|
||
|
|
// 변환 함수들
|
||
|
|
ynToBoolean,
|
||
|
|
booleanToYN,
|
||
|
|
|
||
|
|
// 테이블 관련
|
||
|
|
UnifiedColumnInfo,
|
||
|
|
ColumnTypeInfo,
|
||
|
|
|
||
|
|
// 제어 관련
|
||
|
|
ExtendedButtonTypeConfig,
|
||
|
|
|
||
|
|
// 화면 관련
|
||
|
|
ScreenDefinition,
|
||
|
|
GroupState,
|
||
|
|
} from "@/types";
|
||
|
|
|
||
|
|
// ===== 1단계: 기본 타입 검증 테스트 =====
|
||
|
|
|
||
|
|
export class TypeSafetyTestSuite {
|
||
|
|
/**
|
||
|
|
* 🧪 Test 1: WebType 타입 안전성 검증
|
||
|
|
*/
|
||
|
|
static testWebTypeValidation() {
|
||
|
|
console.log("🧪 Test 1: WebType 타입 안전성 검증");
|
||
|
|
|
||
|
|
// 유효한 WebType들
|
||
|
|
const validWebTypes = [
|
||
|
|
"text",
|
||
|
|
"number",
|
||
|
|
"decimal",
|
||
|
|
"date",
|
||
|
|
"datetime",
|
||
|
|
"select",
|
||
|
|
"dropdown",
|
||
|
|
"radio",
|
||
|
|
"checkbox",
|
||
|
|
"boolean",
|
||
|
|
"textarea",
|
||
|
|
"code",
|
||
|
|
"entity",
|
||
|
|
"file",
|
||
|
|
"email",
|
||
|
|
"tel",
|
||
|
|
"url",
|
||
|
|
"button",
|
||
|
|
];
|
||
|
|
|
||
|
|
// 무효한 타입들 (기존 시스템에서 문제가 되었던 것들)
|
||
|
|
const invalidWebTypes = [
|
||
|
|
"text_area", // 기존에 사용되던 잘못된 타입
|
||
|
|
"VARCHAR", // DB 타입과 혼동
|
||
|
|
"submit", // ButtonActionType과 혼동
|
||
|
|
"container", // ComponentType과 혼동
|
||
|
|
"",
|
||
|
|
null,
|
||
|
|
undefined,
|
||
|
|
];
|
||
|
|
|
||
|
|
validWebTypes.forEach((type) => {
|
||
|
|
const isValid = isWebType(type);
|
||
|
|
console.assert(isValid, `유효한 WebType이 거부됨: ${type}`);
|
||
|
|
if (isValid) {
|
||
|
|
console.log(`✅ Valid WebType: ${type}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
invalidWebTypes.forEach((type) => {
|
||
|
|
const isValid = isWebType(type as any);
|
||
|
|
console.assert(!isValid, `무효한 WebType이 허용됨: ${type}`);
|
||
|
|
if (!isValid) {
|
||
|
|
console.log(`❌ Invalid WebType rejected: ${type}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 2: ComponentData 타입 가드 안전성
|
||
|
|
*/
|
||
|
|
static testComponentTypeGuards() {
|
||
|
|
console.log("\n🧪 Test 2: ComponentData 타입 가드 안전성");
|
||
|
|
|
||
|
|
// 올바른 컴포넌트 생성
|
||
|
|
const widgetComponent: WidgetComponent = {
|
||
|
|
id: "widget-1",
|
||
|
|
type: "widget",
|
||
|
|
position: { x: 0, y: 0 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
widgetType: "text",
|
||
|
|
label: "테스트 텍스트",
|
||
|
|
placeholder: "입력하세요",
|
||
|
|
required: false,
|
||
|
|
readonly: false,
|
||
|
|
webTypeConfig: {},
|
||
|
|
};
|
||
|
|
|
||
|
|
const containerComponent: ContainerComponent = {
|
||
|
|
id: "container-1",
|
||
|
|
type: "container",
|
||
|
|
position: { x: 0, y: 0 },
|
||
|
|
size: { width: 400, height: 300 },
|
||
|
|
label: "컨테이너",
|
||
|
|
children: [],
|
||
|
|
layoutDirection: "vertical",
|
||
|
|
};
|
||
|
|
|
||
|
|
// 타입 가드 테스트
|
||
|
|
console.assert(isWidgetComponent(widgetComponent), "WidgetComponent 타입 가드 실패");
|
||
|
|
console.assert(isContainerComponent(containerComponent), "ContainerComponent 타입 가드 실패");
|
||
|
|
console.assert(!isWidgetComponent(containerComponent), "잘못된 타입이 통과됨");
|
||
|
|
console.assert(!isContainerComponent(widgetComponent), "잘못된 타입이 통과됨");
|
||
|
|
|
||
|
|
// 안전한 캐스팅 테스트
|
||
|
|
const safeWidget = asWidgetComponent(widgetComponent);
|
||
|
|
const safeContainer = asContainerComponent(containerComponent);
|
||
|
|
|
||
|
|
console.assert(safeWidget !== null, "안전한 위젯 캐스팅 실패");
|
||
|
|
console.assert(safeContainer !== null, "안전한 컨테이너 캐스팅 실패");
|
||
|
|
console.assert(asWidgetComponent(containerComponent) === null, "잘못된 캐스팅이 허용됨");
|
||
|
|
|
||
|
|
console.log("✅ Component 타입 가드 모든 테스트 통과");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 3: DB 호환성 (Y/N ↔ boolean) 변환 테스트
|
||
|
|
*/
|
||
|
|
static testYNBooleanConversion() {
|
||
|
|
console.log("\n🧪 Test 3: DB 호환성 Y/N ↔ boolean 변환 테스트");
|
||
|
|
|
||
|
|
// Y/N → boolean 변환
|
||
|
|
console.assert(ynToBoolean("Y") === true, "Y → true 변환 실패");
|
||
|
|
console.assert(ynToBoolean("N") === false, "N → false 변환 실패");
|
||
|
|
console.assert(ynToBoolean("") === false, "빈 문자열 → false 변환 실패");
|
||
|
|
console.assert(ynToBoolean(undefined) === false, "undefined → false 변환 실패");
|
||
|
|
|
||
|
|
// boolean → Y/N 변환
|
||
|
|
console.assert(booleanToYN(true) === "Y", "true → Y 변환 실패");
|
||
|
|
console.assert(booleanToYN(false) === "N", "false → N 변환 실패");
|
||
|
|
|
||
|
|
// 실제 DB 시나리오 시뮬레이션
|
||
|
|
const dbColumnData = {
|
||
|
|
isActive: "Y",
|
||
|
|
isVisible: "N",
|
||
|
|
isPrimaryKey: "Y",
|
||
|
|
isNullable: "N",
|
||
|
|
};
|
||
|
|
|
||
|
|
const convertedData = {
|
||
|
|
isActive: ynToBoolean(dbColumnData.isActive),
|
||
|
|
isVisible: ynToBoolean(dbColumnData.isVisible),
|
||
|
|
isPrimaryKey: ynToBoolean(dbColumnData.isPrimaryKey),
|
||
|
|
isNullable: ynToBoolean(dbColumnData.isNullable),
|
||
|
|
};
|
||
|
|
|
||
|
|
console.assert(convertedData.isActive === true, "DB isActive 변환 실패");
|
||
|
|
console.assert(convertedData.isVisible === false, "DB isVisible 변환 실패");
|
||
|
|
|
||
|
|
console.log("✅ Y/N ↔ boolean 변환 모든 테스트 통과");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 4: 실제 폼 저장 시나리오 시뮬레이션
|
||
|
|
*/
|
||
|
|
static async testFormSaveScenarios() {
|
||
|
|
console.log("\n🧪 Test 4: 실제 폼 저장 시나리오 시뮬레이션");
|
||
|
|
|
||
|
|
// 시나리오 1: 혼합 웹타입 폼 데이터
|
||
|
|
const formData = {
|
||
|
|
userName: "홍길동",
|
||
|
|
userAge: 25,
|
||
|
|
userEmail: "hong@example.com",
|
||
|
|
isActive: true,
|
||
|
|
birthDate: "1999-01-01",
|
||
|
|
userRole: "admin",
|
||
|
|
description: "테스트 사용자입니다.",
|
||
|
|
};
|
||
|
|
|
||
|
|
// 시나리오 2: 컴포넌트별 웹타입 매핑
|
||
|
|
const formComponents: ComponentData[] = [
|
||
|
|
{
|
||
|
|
id: "userName",
|
||
|
|
type: "widget",
|
||
|
|
widgetType: "text",
|
||
|
|
position: { x: 0, y: 0 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
label: "사용자명",
|
||
|
|
columnName: "user_name",
|
||
|
|
webTypeConfig: {},
|
||
|
|
} as WidgetComponent,
|
||
|
|
{
|
||
|
|
id: "userAge",
|
||
|
|
type: "widget",
|
||
|
|
widgetType: "number",
|
||
|
|
position: { x: 0, y: 50 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
label: "나이",
|
||
|
|
columnName: "user_age",
|
||
|
|
webTypeConfig: { min: 0, max: 120 },
|
||
|
|
} as WidgetComponent,
|
||
|
|
{
|
||
|
|
id: "isActive",
|
||
|
|
type: "widget",
|
||
|
|
widgetType: "checkbox",
|
||
|
|
position: { x: 0, y: 100 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
label: "활성화",
|
||
|
|
columnName: "is_active",
|
||
|
|
webTypeConfig: {},
|
||
|
|
} as WidgetComponent,
|
||
|
|
];
|
||
|
|
|
||
|
|
// 타입 안전한 데이터 처리
|
||
|
|
const processedData: Record<string, any> = {};
|
||
|
|
|
||
|
|
for (const component of formComponents) {
|
||
|
|
if (isWidgetComponent(component)) {
|
||
|
|
const { columnName, widgetType } = component;
|
||
|
|
|
||
|
|
if (columnName && widgetType && formData.hasOwnProperty(component.id)) {
|
||
|
|
const rawValue = formData[component.id as keyof typeof formData];
|
||
|
|
|
||
|
|
// 웹타입별 안전한 변환
|
||
|
|
switch (widgetType) {
|
||
|
|
case "text":
|
||
|
|
case "email":
|
||
|
|
case "textarea":
|
||
|
|
processedData[columnName] = String(rawValue);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case "number":
|
||
|
|
case "decimal":
|
||
|
|
processedData[columnName] = Number(rawValue);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case "checkbox":
|
||
|
|
case "boolean":
|
||
|
|
processedData[columnName] = booleanToYN(Boolean(rawValue));
|
||
|
|
break;
|
||
|
|
|
||
|
|
case "date":
|
||
|
|
case "datetime":
|
||
|
|
processedData[columnName] = rawValue ? String(rawValue) : null;
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
console.warn(`처리되지 않은 웹타입: ${widgetType}`);
|
||
|
|
processedData[columnName] = rawValue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
console.log("✅ 폼 데이터 타입 안전 변환:", processedData);
|
||
|
|
|
||
|
|
// 검증: 모든 값이 올바른 타입으로 변환되었는지 확인
|
||
|
|
console.assert(typeof processedData.user_name === "string", "사용자명 타입 변환 실패");
|
||
|
|
console.assert(typeof processedData.user_age === "number", "나이 타입 변환 실패");
|
||
|
|
console.assert(processedData.is_active === "Y" || processedData.is_active === "N", "활성화 상태 변환 실패");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 5: 버튼 제어관리 타입 안전성 테스트
|
||
|
|
*/
|
||
|
|
static testButtonControlTypesSafety() {
|
||
|
|
console.log("\n🧪 Test 5: 버튼 제어관리 타입 안전성 테스트");
|
||
|
|
|
||
|
|
// ButtonActionType 안전성 검증
|
||
|
|
const validActions: ButtonActionType[] = [
|
||
|
|
"save",
|
||
|
|
"cancel",
|
||
|
|
"delete",
|
||
|
|
"edit",
|
||
|
|
"add",
|
||
|
|
"search",
|
||
|
|
"reset",
|
||
|
|
"submit",
|
||
|
|
"close",
|
||
|
|
"popup",
|
||
|
|
"modal",
|
||
|
|
"navigate",
|
||
|
|
"control",
|
||
|
|
];
|
||
|
|
|
||
|
|
validActions.forEach((action) => {
|
||
|
|
console.assert(isButtonActionType(action), `유효한 ButtonActionType 거부: ${action}`);
|
||
|
|
});
|
||
|
|
|
||
|
|
// 무효한 액션 타입들
|
||
|
|
const invalidActions = ["insert", "update", "remove", ""];
|
||
|
|
invalidActions.forEach((action) => {
|
||
|
|
console.assert(!isButtonActionType(action), `무효한 ButtonActionType 허용: ${action}`);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log("✅ 버튼 제어관리 타입 안전성 테스트 통과");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 6: 테이블 컬럼 정보 타입 호환성 테스트
|
||
|
|
*/
|
||
|
|
static testTableColumnTypeCompatibility() {
|
||
|
|
console.log("\n🧪 Test 6: 테이블 컬럼 정보 타입 호환성 테스트");
|
||
|
|
|
||
|
|
// 백엔드에서 받은 원시 컬럼 정보 (ColumnTypeInfo)
|
||
|
|
const backendColumnInfo: ColumnTypeInfo = {
|
||
|
|
columnName: "user_name",
|
||
|
|
displayName: "사용자명",
|
||
|
|
dataType: "varchar",
|
||
|
|
dbType: "character varying(100)",
|
||
|
|
webType: "text", // string 타입 (백엔드)
|
||
|
|
inputType: "direct",
|
||
|
|
detailSettings: JSON.stringify({ maxLength: 100 }),
|
||
|
|
description: "사용자의 이름을 저장하는 컬럼",
|
||
|
|
isNullable: "N", // Y/N 문자열
|
||
|
|
isPrimaryKey: false,
|
||
|
|
defaultValue: "",
|
||
|
|
maxLength: 100,
|
||
|
|
};
|
||
|
|
|
||
|
|
// 프론트엔드 통합 컬럼 정보로 변환 (UnifiedColumnInfo)
|
||
|
|
const unifiedColumnInfo: UnifiedColumnInfo = {
|
||
|
|
columnName: backendColumnInfo.columnName,
|
||
|
|
displayName: backendColumnInfo.displayName,
|
||
|
|
dataType: backendColumnInfo.dataType,
|
||
|
|
dbType: backendColumnInfo.dbType,
|
||
|
|
webType: isWebType(backendColumnInfo.webType) ? (backendColumnInfo.webType as WebType) : "text", // 안전한 타입 변환
|
||
|
|
inputType: backendColumnInfo.inputType,
|
||
|
|
detailSettings: JSON.parse(backendColumnInfo.detailSettings || "{}"),
|
||
|
|
description: backendColumnInfo.description,
|
||
|
|
isNullable: ynToBoolean(backendColumnInfo.isNullable), // Y/N → boolean
|
||
|
|
isPrimaryKey: backendColumnInfo.isPrimaryKey,
|
||
|
|
defaultValue: backendColumnInfo.defaultValue,
|
||
|
|
maxLength: backendColumnInfo.maxLength,
|
||
|
|
companyCode: backendColumnInfo.companyCode,
|
||
|
|
};
|
||
|
|
|
||
|
|
// 검증
|
||
|
|
console.assert(isWebType(unifiedColumnInfo.webType), "WebType 변환 실패");
|
||
|
|
console.assert(typeof unifiedColumnInfo.isNullable === "boolean", "isNullable 타입 변환 실패");
|
||
|
|
console.assert(typeof unifiedColumnInfo.detailSettings === "object", "detailSettings JSON 파싱 실패");
|
||
|
|
|
||
|
|
console.log("✅ 테이블 컬럼 타입 호환성 테스트 통과");
|
||
|
|
console.log("변환된 컬럼 정보:", unifiedColumnInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🧪 Test 7: 복합 시나리오 - 화면 설계 + 데이터 저장 + 제어 실행
|
||
|
|
*/
|
||
|
|
static async testComplexScenario() {
|
||
|
|
console.log("\n🧪 Test 7: 복합 시나리오 - 화면 설계 + 데이터 저장 + 제어 실행");
|
||
|
|
|
||
|
|
try {
|
||
|
|
// Step 1: 화면 정의 생성 (단순화된 버전)
|
||
|
|
const screenDefinition: ScreenDefinition = {
|
||
|
|
screenId: 1001,
|
||
|
|
screenName: "사용자 관리",
|
||
|
|
screenCode: "USER_MANAGEMENT",
|
||
|
|
tableName: "user_info",
|
||
|
|
tableLabel: "사용자 정보",
|
||
|
|
description: "사용자 정보를 관리하는 화면",
|
||
|
|
isActive: "Y",
|
||
|
|
};
|
||
|
|
|
||
|
|
// 개별 컴포넌트 생성
|
||
|
|
const components: ComponentData[] = [
|
||
|
|
{
|
||
|
|
id: "userName",
|
||
|
|
type: "widget",
|
||
|
|
widgetType: "text",
|
||
|
|
position: { x: 10, y: 10 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
label: "사용자명",
|
||
|
|
columnName: "user_name",
|
||
|
|
required: true,
|
||
|
|
webTypeConfig: { maxLength: 50 },
|
||
|
|
} as WidgetComponent,
|
||
|
|
];
|
||
|
|
|
||
|
|
// Step 2: 컴포넌트 타입 안전성 검증
|
||
|
|
components.forEach((component) => {
|
||
|
|
if (isWidgetComponent(component)) {
|
||
|
|
console.assert(isWebType(component.widgetType), `잘못된 위젯타입: ${component.widgetType}`);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Step 3: 그룹 상태 시뮬레이션
|
||
|
|
const groupState: GroupState = {
|
||
|
|
isGrouping: true,
|
||
|
|
selectedComponents: ["userName", "saveButton"],
|
||
|
|
groupTarget: "userForm",
|
||
|
|
groupMode: "create",
|
||
|
|
groupTitle: "사용자 입력 폼",
|
||
|
|
};
|
||
|
|
|
||
|
|
// Step 4: 실제 저장 시뮬레이션
|
||
|
|
const formData = {
|
||
|
|
userName: "테스트 사용자",
|
||
|
|
userEmail: "test@example.com",
|
||
|
|
isActive: true,
|
||
|
|
};
|
||
|
|
|
||
|
|
console.log("✅ 복합 시나리오 모든 단계 성공");
|
||
|
|
console.log("- 화면 정의 생성: ✓");
|
||
|
|
console.log("- 컴포넌트 타입 검증: ✓");
|
||
|
|
console.log("- 그룹 상태 관리: ✓");
|
||
|
|
console.log("- 데이터 저장 시뮬레이션: ✓");
|
||
|
|
} catch (error) {
|
||
|
|
console.error("❌ 복합 시나리오 실패:", error);
|
||
|
|
throw error;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🎯 모든 테스트 실행
|
||
|
|
*/
|
||
|
|
static async runAllTests() {
|
||
|
|
console.log("🎯 타입 안전성 종합 테스트 시작\n");
|
||
|
|
|
||
|
|
try {
|
||
|
|
this.testWebTypeValidation();
|
||
|
|
this.testComponentTypeGuards();
|
||
|
|
this.testYNBooleanConversion();
|
||
|
|
await this.testFormSaveScenarios();
|
||
|
|
this.testButtonControlTypesSafety();
|
||
|
|
this.testTableColumnTypeCompatibility();
|
||
|
|
await this.testComplexScenario();
|
||
|
|
|
||
|
|
console.log("\n🎉 모든 타입 안전성 테스트 통과!");
|
||
|
|
console.log("✅ 화면관리, 제어관리, 테이블타입관리 시스템의 타입 안전성이 보장됩니다.");
|
||
|
|
|
||
|
|
return {
|
||
|
|
success: true,
|
||
|
|
passedTests: 7,
|
||
|
|
failedTests: 0,
|
||
|
|
message: "모든 타입 안전성 테스트 통과",
|
||
|
|
};
|
||
|
|
} catch (error) {
|
||
|
|
console.error("❌ 타입 안전성 테스트 실패:", error);
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
passedTests: 0,
|
||
|
|
failedTests: 1,
|
||
|
|
message: `테스트 실패: ${error}`,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 🔥 스트레스 테스트 시나리오
|
||
|
|
export class StressTestScenarios {
|
||
|
|
/**
|
||
|
|
* 🔥 극한 상황 테스트: 잘못된 타입들의 혼재
|
||
|
|
*/
|
||
|
|
static testMixedInvalidTypes() {
|
||
|
|
console.log("🔥 극한 상황 테스트: 잘못된 타입들의 혼재");
|
||
|
|
|
||
|
|
// API로부터 받을 수 있는 다양한 잘못된 데이터들
|
||
|
|
const corruptedData = [
|
||
|
|
{ webType: "text_area", expected: false }, // 기존 잘못된 타입
|
||
|
|
{ webType: "VARCHAR(255)", expected: false }, // DB 타입 혼입
|
||
|
|
{ webType: "submit", expected: false }, // ButtonActionType 혼입
|
||
|
|
{ webType: "", expected: false }, // 빈 문자열
|
||
|
|
{ webType: null, expected: false }, // null
|
||
|
|
{ webType: undefined, expected: false }, // undefined
|
||
|
|
{ webType: 123, expected: false }, // 숫자
|
||
|
|
{ webType: {}, expected: false }, // 객체
|
||
|
|
{ webType: "text", expected: true }, // 올바른 타입
|
||
|
|
];
|
||
|
|
|
||
|
|
corruptedData.forEach(({ webType, expected }) => {
|
||
|
|
const result = isWebType(webType as any);
|
||
|
|
console.assert(
|
||
|
|
result === expected,
|
||
|
|
`타입 검증 실패: ${JSON.stringify(webType)} → expected: ${expected}, got: ${result}`,
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log("✅ 극한 상황 타입 검증 테스트 통과");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 🔥 대량 데이터 처리 시나리오
|
||
|
|
*/
|
||
|
|
static testBulkDataProcessing() {
|
||
|
|
console.log("🔥 대량 데이터 처리 시나리오");
|
||
|
|
|
||
|
|
// 1000개의 컴포넌트 생성 및 타입 검증
|
||
|
|
const components: ComponentData[] = [];
|
||
|
|
const webTypes: WebType[] = ["text", "number", "date", "select", "checkbox"];
|
||
|
|
|
||
|
|
for (let i = 0; i < 1000; i++) {
|
||
|
|
const randomWebType = webTypes[i % webTypes.length];
|
||
|
|
const component: WidgetComponent = {
|
||
|
|
id: `widget-${i}`,
|
||
|
|
type: "widget",
|
||
|
|
widgetType: randomWebType,
|
||
|
|
position: { x: i % 100, y: Math.floor(i / 100) * 50 },
|
||
|
|
size: { width: 200, height: 40 },
|
||
|
|
label: `Component ${i}`,
|
||
|
|
webTypeConfig: {},
|
||
|
|
};
|
||
|
|
components.push(component);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 모든 컴포넌트 타입 검증
|
||
|
|
let validCount = 0;
|
||
|
|
components.forEach((component) => {
|
||
|
|
if (isWidgetComponent(component) && isWebType(component.widgetType)) {
|
||
|
|
validCount++;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
console.assert(validCount === 1000, `대량 데이터 검증 실패: ${validCount}/1000`);
|
||
|
|
console.log(`✅ 대량 데이터 처리 성공: ${validCount}/1000 컴포넌트 검증 완료`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Export for use in tests
|
||
|
|
export default TypeSafetyTestSuite;
|