pixalynx/edge-connector
Configures USB-A, Micro-USB, and USB-C PCB-edge connectors with exposed copper contacts and automatically shaped, positioned board tongues.
- Version
- 1.0.0
- License
- GPL-3.0-only
- Stars
- 0
UsbEdgeConnectorBoard.test.mjs
import { expect, test } from "bun:test"
import { jsx, jsxs } from "react/jsx-runtime"
import { Circuit } from "tscircuit"
import { UsbEdgeConnectorBoard } from "./index.tsx"
import { getUsbEdgeBoardLayout } from "./UsbEdgeConnectorBoard.tsx"
const counts = { "usb-a": 4, "usb-c": 24, "micro-usb": 5 }
function inside(point, polygon) {
let result = false
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const a = polygon[i], b = polygon[j]
if ((a.y > point.y) !== (b.y > point.y) &&
point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x) result = !result
}
return result
}
for (const connector of Object.keys(counts)) {
for (const edge of ["top", "right", "bottom", "left"]) {
test(`${connector} on ${edge}: board bounds, offset, rotation, copper faces, and contained pads`, async () => {
const circuit = new Circuit()
circuit.add(jsx(UsbEdgeConnectorBoard, {
connector, edge, offset: 1, width: 24, height: 28,
connectorProps: { name: "J1" },
}))
await circuit.renderUntilSettled()
const json = circuit.getCircuitJson()
const board = json.find(e => e.type === "pcb_board")
expect(board.width).toBe(24)
expect(board.height).toBe(28)
expect(board.thickness).toBe(connector === "usb-a" ? 2 : 0.6)
expect(Math.min(...board.outline.map(p => p.x))).toBe(-12)
expect(Math.max(...board.outline.map(p => p.x))).toBe(12)
expect(Math.min(...board.outline.map(p => p.y))).toBe(-14)
expect(Math.max(...board.outline.map(p => p.y))).toBe(14)
const component = json.find(e => e.type === "pcb_component")
expect(component.rotation).toBe({ top: 0, right: 270, bottom: 180, left: 90 }[edge])
expect(component.insertion_direction).toBe(`from_${edge}`)
expect(component.center[edge === "top" || edge === "bottom" ? "x" : "y"]).toBeCloseTo(1)
const pads = json.filter(e => e.type === "pcb_smtpad")
expect(pads).toHaveLength(counts[connector])
expect(pads.filter(p => p.layer === "bottom")).toHaveLength(connector === "usb-c" ? 12 : 0)
for (const pad of pads) {
for (const dx of [-1, 1]) for (const dy of [-1, 1]) {
expect(inside({ x: pad.x + dx * pad.width / 2, y: pad.y + dy * pad.height / 2 }, board.outline)).toBe(true)
}
}
expect(json.filter(e => e.type.endsWith("error"))).toEqual([])
})
}
}
test("board children and connector wiring share the same circuit without manual placement", async () => {
const circuit = new Circuit()
circuit.add(jsxs(UsbEdgeConnectorBoard, {
connector: "usb-a", width: 20, height: 25,
connectorProps: { name: "USB", connections: { VBUS: "R1.pin1" }, schX: -3 },
children: [jsx("resistor", { name: "R1", resistance: "10k", footprint: "0402", pcbX: 0, pcbY: -3, schX: 1 })],
}))
await circuit.renderUntilSettled()
const json = circuit.getCircuitJson()
const resistor = json.find(e => e.type === "source_component" && e.name === "R1")
const pcb = json.find(e => e.type === "pcb_component" && e.source_component_id === resistor.source_component_id)
expect(pcb.center).toEqual({ x: 0, y: -3 })
const sourcePorts = json.filter(e => e.type === "source_port")
const vbus = sourcePorts.find(p => p.name === "VBUS")
const r1pin1 = sourcePorts.find(p => p.source_component_id === resistor.source_component_id && p.pin_number === 1)
const trace = json.find(e => e.type === "source_trace" && e.connected_source_port_ids.includes(vbus.source_port_id))
expect(trace.connected_source_port_ids).toContain(r1pin1.source_port_id)
})
test("invalid sizes and offsets fail clearly rather than producing a broken outline", () => {
const defaults = { connector: "usb-a", width: 20, height: 24 }
for (const override of [
{ width: 0 }, { height: -1 }, { width: Infinity }, { offset: NaN },
{ width: 10 }, { height: 8 }, { offset: 8 }, { edge: "left", height: 10 },
]) {
expect(() => getUsbEdgeBoardLayout({ ...defaults, ...override })).toThrow()
}
})