neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
翻译准备中
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证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