Audience: developers & AI agents writing specs · Scope: the secret-gated HTTP endpoint + the support client that specs use to arrange fixtures and read state · Last reviewed: 2026-07-11
Part of Testing. Reuse these commands in new specs instead of writing DB or CLI glue.
TL;DR — Playwright runs in Node; the app is PHP/Joomla. They meet through one authenticated HTTP
endpoint (ConfigboxControllerBctestsupport → BcTestSupport) that runs the app's own code to inspect and
prepare state, run the deal-update flow in capture mode, and mint follow-up tokens. Specs call it through the
synchronous support client (tests/support/cli.ts). Using the app's own code keeps tests honest and
avoids duplicating schema knowledge.
The endpoint & auth
GET {BASE_URL}/index.php?option=com_configbox&controller=bctestsupport&task=run&command=<cmd>&arg1=<…>&arg2=<…>
Header: X-BC-Test-Support-Secret: <the environment's test_support_secret setting>
- Fail-closed & secret-gated. It works only when the per-environment setting
test_support_secret
(Backend → Settings → Functional Test Harness) is set and the caller presents the same value
(constant-time compare). A blank setting disables the endpoint (403) — leave it blank except while
running the suite. Put the matching value in tests/.env as TEST_SUPPORT_SECRET.
- Capture is inline. The
process* commands run in capture mode and return the intercepted Pipedrive
payloads in the response (captures), which the client mirrors to tests/.captures/. Nothing is sent.
- The same logic is also a server-local CLI (
docroot/cli/cb_pipedrive_test_support.php) for manual use on
the box; the suite no longer needs it.
The client (tests/support/cli.ts)
support.* is synchronous (curl + execFileSync), so call sites read top-to-bottom with no await.
Companion helpers: support/captures.ts (capturesForSerial(serial)), support/seedQuote.ts
(seedDecorativeQuote(page)), support/followupForm.ts (form gestures).
Commands
Every command below is reachable as support.<method>(…). R = read-only, W = mutates test data,
★ = real external write (opt-in / live only).
Harness & config
| Command | support.… | Purpose | |
|---|
mode | mode() | resolved capture/send mode, environment, DEV org id | R |
field-keys | fieldKeys() | the settings-sourced custom-field keys the payload uses (env-specific hashes) | R |
page-urls | pageUrls() | server-resolved SEF URLs for the My Quotes + login pages (assert a redirect target without hard-coding) | R |
Quote state & fixtures
| Command | support.… | Purpose | |
|---|
quote-state <serial> | quoteState() / latestQuote() | every revision's pipedrive_* columns (+ id/name/revision/stage/dates/oot) | R |
set-quote-owner <serial> <cbUserId> | setQuoteOwner() | reassign every revision to another owner (the non-owner test) | W |
delete-quote <serial> | deleteQuote() | hard-delete every revision + child rows (cleanup; no Pipedrive) | W |
reset-feedback <serial> | resetFeedback() | clear the Quote Follow-Up feedback so the page renders the fresh form state | W |
Quote Follow-Up
| Command | support.… | Purpose | |
|---|
seed-stages / clear-stages | seedStages() / clearStages() | populate/remove a deterministic synthetic stage set (no live import needed) | W |
mint-followup-token <serial> [expired] | mintFollowupToken() | sign a grant token for the serial's agent (open the no-login page authorized; not a login) | R |
set-followup-api-secret <secret> | setFollowupApiSecret() | set/clear the Link API shared secret (auth matrix); returns the previous value to restore | W |
Stage-sync
| Command | support.… | Purpose | |
|---|
stage-sync-rows <serial> | stageSyncRows() / latestStageSyncRow() | the always-on recorder's rows for a serial | R |
clear-stage-sync <serial> | clearStageSync() | delete a serial's sync rows (cleanup — they have no FK to the quote) | W |
Nudge
| Command | support.… | Purpose | |
|---|
set-stage-cadence <stageId> <csv> | setStageCadence() | set a stage's nudge cadence ("small,mid,large", "0,0,0" = due now); returns previous | W |
set-nudge-gates <excl> <incl> | setNudgeGates() | flip the internal/test deal-type gates; returns previous | W |
collect-due-rows <serial> | collectNudgeDueRow() | run the real due computation for one serial without writing a sheet — is it due, with what bucket/anchor | R |
Deal-update flow (capture)
| Command | support.… | Purpose | |
|---|
schedule <serial> | schedule() | flag the latest revision for a deal update (drive the runner without the UI) | W |
set-deal-id <serial> <dealId> | setDealId() | link a quote to an existing deal id (the update-path fixture) | W |
process / process-serial <serial> | process() / processSerial() | run the deal update (whole queue / one serial) in capture mode; returns the captured payloads | W |
clear-captures | clearCaptures() | empty the local capture file (server-side no-op) | R |
Live / real destinations (★ opt-in, DEV org 6034 only)
| Command | support.… | Purpose | |
|---|
read-deal <serial> | readDeal() | read the live Pipedrive deal (stage_id/pipeline_id/status/…) | R |
create-fixture-deal <serial> | createFixtureDeal() | create a throwaway DEV-org deal + link it (so the push takes the guard-safe update path) | ★ |
delete-deal <serial> | deleteDeal() | delete the linked real deal (live-smoke teardown) | ★ |
process-serial <serial> (send) | processSerialLive() | run the deal update in send mode (real write; org-6034 guard applies) | ★ |
export-sheet / read-sheet-rows <serial> | exportSheet() / readSheetRows() | run the real stage-sync sheet export / read it back | ★ / R |
build-nudge-sheet / read-nudge-sheet-rows <serial> | buildNudgeSheet() / readNudgeSheetRows() | run the real nudge reconcile / read it back | ★ / R |
Adding a command
system_overrides/BcTestSupport.php — add a case in run() calling a new private static method
(read state, or mutate test data; keep it test-only and idempotent-friendly). A setter that changes a
setting should return the previous value so the spec can restore it.
tests/support/cli.ts — add a support.<method>() wrapper (typed return) that calls call('<cmd>', …).
- Document it — add a row to the right table above, so the next spec reuses it.
Safety
These are powerful, test-only mutations (delete quotes, reassign owners, mint grant tokens, write
settings). They are reachable only through the secret-gated controller (or the server-local CLI) — never
wire BcTestSupport to an unauthenticated path. Real external writes are confined to DEV org 6034 by the
always-on guard. See ../pipedrive/testing.md for the capture/guard detail.