neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Test helpers that locate Apache Wicket components by type, wicket:id, model object and position instead of string paths
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Readable, refactoring-proof Apache Wicket tests.
WicketTester addresses components by string paths such as "orders:1:customer". Those paths
break as soon as a component gets wrapped in a container or a list changes order, and they tell
the reader nothing about intent. wicket-testkit locates a component by what it is: its type,
wicket:id, model object, visibility, or position inside another component. It then acts and
asserts on that component through your normal WicketTester.
// before
tester.assertLabel("orders:1:customer", "Globex");
tester.clickLink("orders:1:ship");
// after
kit.assertLabel(locate(Label.class).withId("customer").inRowOf(order), "Globex");
kit.click(locate(AjaxLink.class).withId("ship").inRowOf(order));
Add it in test scope. It needs Wicket 10 and Java 17 or newer, and uses the wicket-core and
wicket-tester your project already has, so your Wicket version wins.
<dependency>
<groupId>dev.jbaby</groupId>
<artifactId>wicket-testkit</artifactId>
<version>0.2.0</version>
<scope>test</scope>
</dependency>
Gradle: testImplementation("dev.jbaby:wicket-testkit:0.2.0")
A Locator starts with a type and is narrowed down step by step. A component matches when it
meets every criterion.
import static dev.jbaby.wicket.testkit.locator.Locator.locate;
locate(Label.class) // every Label, subclasses included
.withId("customer") // with this wicket:id
.withModelObject("ACME") // whose model object equals this
.visible() // visible in hierarchy
.enabled() // enabled in hierarchy
.inside(locate(Panel.class).withId("details")) // with a matching ancestor
.inRowOf(order) // in the ListView or DataView row of this element
.matching(label -> label.getDefaultModelObjectAsString().startsWith("A"), "starts with A"); // anything else
Form fields can be found by their label, and model objects without a useful equals, such as
entities, by a check:
locate(TextField.class).withLabel("Customer") // setLabel or <wicket:label>
locate(OrderPanel.class).withModelObject(Order.class, o -> o.id() == 42, "has id 42")
locate(Label.class).withId("total").inRowOf(Order.class, o -> o.id() == 42, "has id 42")
Locators are immutable. Every step returns a new locator, so you can keep a base locator and refine it. A locator finds components among the descendants of a page or any other container:
Label customer = locate(Label.class).withId("customer").inRowOf(order).one(page); // exactly one, or AssertionError
List<Label> all = locate(Label.class).withId("customer").all(page); // every match, in tree order
boolean any = locate(Link.class).withId("next").existsIn(page);
A locator doesn't filter by visibility unless you call visible(). That way the same locator
works for asserting that something is invisible.
Give a locator a name in your domain's words, and its failure messages start with that name:
locate(AjaxLink.class).withId("ship").inRowOf(order).named("the Ship button of order 42")
Expected exactly one match for the Ship button of order 42, an AjaxLink with id "ship" in the row of Order[id=42, customer=Globex] in OrdersPage, but found none.
Refining a named locator returns one without the name, because the name no longer fits it.
The locating layer (dev.jbaby.wicket.testkit.locator) uses nothing from wicket-tester, so it
works on any component tree.
WicketTestkit wraps the WicketTester you already have and leaves it usable as before. Every
method resolves its locator against the last rendered page to exactly one component. It then
hands that component to the matching WicketTester method (shown in the comments below), so
Wicket's own behaviour applies unchanged.
WicketTestkit kit = WicketTestkit.of(tester);
tester.startPage(OrdersPage.class);
kit.click(locate(AjaxLink.class).withId("ship").inRowOf(order)); // clickLink
kit.ajax(locate(WebMarkupContainer.class).withId("row").inRowOf(order), "dblclick"); // executeAjaxEvent
kit.assertLabel(locate(Label.class).withId("status").inRowOf(order), "shipped"); // assertLabel
kit.assertOnAjaxResponse(locate(Label.class).withId("status").inRowOf(order)); // assertComponentOnAjaxResponse
kit.assertVisible(locate(Link.class).withId("details").inRowOf(order)); // assertVisible
kit.assertInvisible(locate(Label.class).withId("secret")); // assertInvisible
kit.assertEnabled(locate(Button.class).withId("save")); // assertEnabled
kit.assertDisabled(locate(Link.class).withId("archive")); // assertDisabled
kit.assertModelObject(locate(TextField.class).withId("customer"), "ACME"); // assertModelValue
kit.assertFeedback(locate(FeedbackPanel.class).visible(), "Shipped order 42"); // assertFeedback
kit.assertFeedbackOn(locate(TextField.class).withId("customer"), "'Customer' is required."); // assertFeedbackMessages
kit.assertCount(locate(Link.class).withId("ship").visible(), 0);
For any WicketTester method without a counterpart here, pathOf gives you the path, and for any
other check, one gives you the component:
tester.assertComponent(kit.pathOf(locate(Panel.class).withId("details")), DetailsPanel.class);
assertThat(kit.one(locate(TextField.class).withId("customer")).isRequired()).isTrue();
form wraps a FormTester for the located form. Fields and buttons are located inside that
form only.
kit.form(locate(Form.class).withId("order"))
.set(locate(TextField.class).withId("customer"), "Globex")
.choose(locate(DropDownChoice.class).withId("country"), "Germany")
.chooseAll(locate(CheckBoxMultipleChoice.class).withId("extras"), "insurance", "tracking")
.check(locate(CheckBox.class).withId("giftWrap"))
.submit(locate(AjaxButton.class).withId("save"));
choose selects the choice that equals the one you give, so the test keeps working when the
choices are reordered; if the field has no such choice, the failure lists the ones it has.
select(field, index) selects by position. chooseAll replaces a multiple choice's selection,
and check and uncheck set check boxes.
submit() submits without a button. submit(button) submits through the button, using Ajax if it
is an AjaxButton or AjaxSubmitLink, as FormTester does.
To fire an Ajax event on a field, such as "change" for an AjaxFormComponentUpdatingBehavior, use
the form helper's ajax. It sends the values set so far, so the behavior sees the new input.
(kit.ajax sends no form input, and would leave the field's model empty.)
kit.form(locate(Form.class).withId("order"))
.choose(locate(DropDownChoice.class).withId("country"), "Germany")
.ajax(locate(DropDownChoice.class).withId("country"), "change");
A form helper lives for one request. Until the tester handles another one, kit.form(...) returns
the same helper, so a page object can fill in a form step by step. After a submit, an Ajax event
or any other request, call kit.form(...) again. For anything the helper doesn't offer, such as
files, formTester() returns the FormTester behind it.
assertRows compares the rows of a repeater with a table, the way a specification gives
examples. The header names the wicket:ids to read in every row:
kit.assertRows(locate(ListView.class).withId("orders"), """
| customer | status |
| ACME | open |
| Globex | shipped |
""");
A cell holds the component's model object as Wicket renders it, without escaping, so
O'Brien & Sons is written as it reads. Hidden rows are left out, hidden components count as
empty, and whitespace counts as a browser shows it. When the rows differ, the failure carries
both tables, padded alike, as expected and actual values, so your IDE shows them side by side:
a ListView with id "orders" (at orders): the rows differ
expected:
| customer | status |
| ACME | open |
| Globex | shipped |
but was:
| customer | status |
| ACME | open |
| Globex | open |
Every failure is an AssertionError that says what was searched for and what was found.
A locator that matches nothing lists its near misses: components that meet every criterion but one. A component of another type or a hidden one comes first.
Expected exactly one match for a Label with id "customr" in the row of Order[id=42, customer=Globex] in OrdersPage, but found none.
Near misses (all criteria but one):
- orders:1:customer (has id "customer")
- orders:1:status (has id "status")
When no component comes that close, the message lists the components of the locator's type, closest first, with everything that differs:
Expected exactly one match for a Label with id "customer" in the row of Order[id=99] in OrdersPage, but found none.
Components of type Label:
- orders:0:customerName (is not in the row of Order[id=99]; has id "customerName")
- orders:1:customerName (is not in the row of Order[id=99]; has id "customerName")
A locator that matches several components lists them:
Expected exactly one match for an AjaxLink with id "ship" in OrdersPage, but found 3:
- orders:0:ship
- orders:1:ship
- orders:2:ship
When a WicketTester check fails, the locator and the component's path go in front of its
message. Expected and actual values are kept, so your IDE still offers its diff:
a Label with id "customer" in the row of Order[id=42, customer=Globex] (at orders:1:customer): expected: <ACME> but was: <Globex>
Wrap locators in a page object, and your tests read in the words of your domain:
class OrdersPageObject {
private final WicketTestkit kit;
OrdersPageObject(WicketTestkit kit) {
this.kit = kit;
}
Row rowOf(Order order) {
return new Row(order);
}
class Row {
private final Order order;
Row(Order order) {
this.order = order;
}
void ship() {
kit.click(locate(AjaxLink.class).withId("ship").inRowOf(order));
}
void assertStatus(String status) {
kit.assertLabel(locate(Label.class).withId("status").inRowOf(order), status);
}
}
}
@Test
void shipsAnOrder() {
tester.startPage(OrdersPage.class);
var ordersPage = new OrdersPageObject(WicketTestkit.of(tester));
ordersPage.rowOf(order).ship();
ordersPage.rowOf(order).assertStatus("shipped");
}
This exact page object runs as a test in
src/test/java/dev/jbaby/wicket/testkit/examples.
Name the locators in a page object with named, and failures speak the domain's words as well.
visitChildren.visible(), withId, inside or inRowOf, and use assertCount for "none".inside.tester.startComponentInPage(component), you can
locate everything inside the component, but not the component itself: WicketTester's paths
can't address it.ListItems. inRowOf covers ListView (including PropertyListView and
PageableListView), RefreshingView and DataView, whose Item extends ListItem.
Loop items and plain RepeatingView children are not rows; use inside or matching
for them.select and choose fail on a field with a
FormComponentUpdatingBehavior, because FormTester would send a request for it at once and
lose the values set so far. Select it through formTester() if you mean it.withLabel sees a label set by setLabel or by a <wicket:label> in the markup.
A plain <label wicket:for> sets none.wicket:id. So assertRows can't compare a DataTable,
whose cells all have the id cell.AjaxFallbackButton extends Button, so FormTester, and with it
submit(button), submits through it without Ajax.WicketTester, not BaseWicketTester. The assertions exist only on WicketTester.an before any vowel letter, so a comes out as
.The Javadoc is written as /// Markdown, which needs JDK 23 or newer to render. The project
compiles with --release 17 and builds on JDK 25:
./mvnw verify
Each package's spec lives in its package-info.java, as EARS requirements with ids like R2.3.
Every requirement has a test whose @DisplayName starts with its id, and SpecTraceabilityTests
fails the build on any gap.
wicket-testkit builds on the idea of
otto-de/enhanced-wickettester (Apache 2.0),
which selected Wicket components by matchers instead of paths, back in Wicket 7. wicket-testkit is a
from-scratch rewrite for Wicket 10 and shares no code with it. It wraps WicketTester instead of
subclassing it, needs no TestNG, Hamcrest or commons-lang, and adds the row shortcut and the
failure messages. Wicket's own WicketTester finds components by path, by markup tag, and by
wicket:id, the last only after startComponentInPage.
The word "locator" is borrowed from Playwright.
UserPanelan UserPanel