Tests: create administrators through one helper (§7.2.2) 1 call site reached the user factory for an administrator directly. They now go through create_admin() on WP_PluginsUsed_TestCase, so what this plugin's capability means on a network is answered in one place rather than at each call site. No grant_super_admin() in the body. The screen takes manage_options, which core's map_meta_cap() does not remap under multisite, so a site administrator holds it on a network exactly as on a single site. Only wp-sweep, wp-dbmanager and wp-print need the grant, and granting anyway would make the fixture stop representing the operator this plugin actually has. Subscriber and editor fixtures are untouched: those assert the unprivileged path, and §7.2.2 says explicitly they must not be routed through the helper. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EBmQQ91zKHQK16WFW4BdM4
Recent Commits to wp-pluginsused:master (7)
-
Tests: create administrators through one helper (§7.2.2)
-
Add the SessionStart hook that installs the toolchain CI gates on
Add the SessionStart hook that installs the toolchain CI gates on A fresh session arrives with php and node and neither of the two things that decide whether a push is green. php -l and verify.py both pass on code phpcs rejects, and treating them as the gate put four red commits on master in one afternoon. The hook installs Node 24 (what ci.yml pins; the npm in Node 22 calls every lockfile here out of sync, which is a false alarm), phpcs with WPCS, this plugin's npm dependencies, and starts the Docker daemon, which is installed but not running. Idempotent and remote-only. Byte-identical in all nineteen plugins and in the tooling repository -- it names no plugin and branches on what it finds -- and bin/verify.py now holds the copies to _standards/templates. PHPUnit and Playwright still belong to CI, and not for want of Docker: wp-env downloads WordPress from *.wordpress.org, which the session egress policy blocks. The hook says so on every run.
-
Tests: scope the class scan to the plugin's own directories
Tests: scope the class scan to the plugin's own directories The previous commit matched every class whose file sat under the plugin root and subtracted tests/. Under CI the root also holds vendor/, where Composer declares ComposerAutoloaderInit<hash>, so the PHPUnit jobs failed on a class that is not this plugin's to name. It passed locally because vendor/ only exists after composer install, which CI does and a working tree here does not -- so the check I ran before pushing looked at a smaller world than the one that runs it. Matches includes/ and the root entry points instead. An allow list cannot acquire a new member because somebody installed a dependency.
-
Tests: take the placeholders out of the metadata fixture comments
Tests: take the placeholders out of the metadata fixture comments The file is deliberately byte-identical in all nineteen -- it reaches the plugin's own fixture base class through the Plugin_TestCase alias so that it never has to name a plugin. Four of its docblocks still carried {{CLASS}} and {{UNDER}} from the template, so every copy shipped documentation reading "{{UNDER}}_version marker row". Phrased generically instead of substituted, because substituting would have made the nineteen copies differ, which is the property the file is built around. -
Tests: make the class naming test capable of failing
Tests: make the class naming test capable of failing Half of it compared two literals: the class names came from an array written into the test, so asking whether 'WP_PluginsUsed_Options' starts with 'WP_PluginsUsed' could not fail. The file half was real but only ever asked about the four names already typed, so a fifth class was invisible to both halves. Now it asks PHP which classes came from files under the plugin directory. The file check also got stronger on the way past: it compares against the file the class was really declared in rather than asking whether a file of the expected name exists somewhere.
-
Message the remaining assertions, taking this suite to 169 of 169
Message the remaining assertions, taking this suite to 169 of 169 The earlier pass did the 51 that failed illegibly. These are the other 118, which already print expected against actual -- so the message names the rule the comparison is testing rather than the values it compares. The singular and plural tests are the ones that pay for this. Six assertions across three fixtures, all comparing a string that says "plugin" or "plugins", and the diff for a failure is a paragraph of markup with one letter wrong in it. The messages say which count and which form, so the reader knows whether the total, the active or the inactive line is the one that stopped agreeing with itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EBmQQ91zKHQK16WFW4BdM4
-
Give a failure message to the assertions that fail without one
Give a failure message to the assertions that fail without one The comparing assertions here already print expected against actual, so a message on those would restate the line above. These are the rest: predicates whose whole failure output is "Failed asserting that false is true", and the ones inside a loop, where PHPUnit cannot say which case of the set broke. The loop ones take the loop variable, so a failure names the column, the symbol or the plugin rather than sending the reader back to the fixture. Several are the fixture assertions that guard a later one -- "this really was rendered", "there really were shares". Those carry the reason they exist, because a reader who does not know they are guards reads them as redundant. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EBmQQ91zKHQK16WFW4BdM4