import { describe, expect, it } from 'vitest'; import { buildPier } from '../src/core/geometry'; import { assemblyBars, assemblyJs, b9Bars, bottomBars, crossBars, sideBars } from '../src/core/rebar/footing'; import { DEFAULT_FOOTING_REBAR } from '../src/core/rebar/footing-settings'; import { footingSectionSvg } from '../src/view/footing-section-svg'; import { loadP1 } from './helpers'; const countMark = (svg: string, cls: string, bar: string) => svg.split(`class="${cls}" data-bar="${bar}"`).length - 1; describe('확대기초 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추천안 1단계)', () => { const m = buildPier(loadP1()); const foot = m.footings[0]; const L = foot.length * 1000; const W = foot.width * 1000; const H = (foot.top - foot.bottom) * 1000; const fs = DEFAULT_FOOTING_REBAR; const svg = footingSectionSvg(m); it('point and line counts match the rebar table families', () => { const bottom = bottomBars(L, W, H, fs); expect(countMark(svg, 'b1', 'B1')).toBe(bottom.find((b) => b.name === 'B1')!.count); expect(countMark(svg, 'b2', 'B2')).toBe(bottom.find((b) => b.name === 'B2')!.count); expect(countMark(svg, 'b4', 'B4')).toBe(bottom.find((b) => b.name === 'B4')!.count); expect(countMark(svg, 'b9', 'B9')).toBe(b9Bars(L, W, [], 2000, fs).rows); expect(countMark(svg, 'b10', 'B10-1')).toBe(sideBars(L, W, H, fs).find((b) => b.name === 'B10-1')!.count); expect(countMark(svg, 'b11', 'B11')).toBe(assemblyJs(H, fs).length); expect(countMark(svg, 'b12', 'B12')).toBe(assemblyBars(L, W, H, fs).find((b) => b.name === 'B12')!.count); for (const name of ['B5', 'B6', 'B7', 'B8']) expect(countMark(svg, 'b5', name)).toBe(1); expect(crossBars(L, W, H, fs).length).toBe(4); }); it('shows the width, the grid string, and the B10 levels as dimensions', () => { expect(svg).toContain('폭 8150'); expect(svg).toContain('8@200=1600'); expect(svg).toContain(`${fs.cBottom}`); }); it('has one bubble per highlighted bar family', () => { for (const name of ['B1', 'B2', 'B3', 'B4', 'B5', 'B11', 'B10-1']) expect(svg).toContain(`data-bubble="${name}"`); }); });