Forms: Allow submitting form previews as test responses#48057
Conversation
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage SummaryCoverage changed in 13 files. Only the first 5 are listed here.
Full summary · PHP report · JS report If appropriate, add one of these labels to override the failing coverage check:
Covered by non-unit tests
|
| if ( ! current_user_can( 'edit_post', $form_id ) ) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Wondering if “previewing unpublished posts” type capability would be more suitable here :thinking_face:
| * @return The badge element. | ||
| */ | ||
| function FormPreviewBadge( { previewUrl }: { previewUrl?: string | null } ) { | ||
| const label = __( 'Form Preview', 'jetpack-forms' ); |
There was a problem hiding this comment.
| const label = __( 'Form Preview', 'jetpack-forms' ); | |
| const label = __( 'Form preview', 'jetpack-forms' ); |
We should always use sentence case.
Follow-ups from review feedback on #48057: - Replace the hidden-field + nonce injection in form preview rendering with a flag baked into the signed JWT. Feedback_Source::get_current() now reads Form_Preview::is_preview_mode() at render time and records is_test=true on the source, which travels tamper-proof inside the JWT to submission. JWTs issued before this change omit the flag and continue to behave as regular submissions. - Remove the now-unused inject_preview_submission_fields() helper, verify_preview_submission() helper, and the three PREVIEW_SUBMIT_* constants from Form_Preview. - Drop the test-feedback special case in Feedback::save(); test responses are now created as STATUS_UNREAD like any other response so they contribute to the unread count. - Add aria-label="Test response" to the inline Test badge in the dashboard From column so screen readers get a complete label. - Add two PHPUnit round-trip tests covering the JWT backward-compat contract: a JWT issued in preview mode marks the decoded form as a test submission; a JWT issued outside preview mode (or from a cached HTML fragment predating this feature) decodes to a regular submission. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
This is great work, @enejb! So glad you're working on this. 🙌
The badge placement pushes the whole row down, which isn't ideal. Could we use the same white badge as in the dataViews, but place it in the same row (centered) with name and email, just place it on the other side (right)?
I'd place the warning outside the content, and above the content card at the top.
The warning makes it feel like something is wrong, but test data is nothing dangerous. I wonder if we even need to announce/share this?
I feel like the source should still be the actual name of the form.
The badge in the front breaks the flow, let's add at in the end. And also I'd consider the badge to be either blue or white, one of them, because two of them clashes together. I hope this is helpful. 😅 |
Form preview now lets you submit the form to test the full submission flow end to end. Responses created from preview are stored normally in the inbox but flagged as test responses: clearly badged in the dashboard list and detail panel, prefixed with [TEST] in the notification email with a banner, excluded from the default CSV export, and excluded from exports unless explicitly selected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move CSVExport and GoogleDriveExport components above the selected-test warning and remove the duplicate render. The Google Drive export remains conditionally rendered when enabled and preserves the autoConnect prop. This reordering makes export controls visible before the warning about exporting test responses.
Follow-ups from review feedback on #48057: - Replace the hidden-field + nonce injection in form preview rendering with a flag baked into the signed JWT. Feedback_Source::get_current() now reads Form_Preview::is_preview_mode() at render time and records is_test=true on the source, which travels tamper-proof inside the JWT to submission. JWTs issued before this change omit the flag and continue to behave as regular submissions. - Remove the now-unused inject_preview_submission_fields() helper, verify_preview_submission() helper, and the three PREVIEW_SUBMIT_* constants from Form_Preview. - Drop the test-feedback special case in Feedback::save(); test responses are now created as STATUS_UNREAD like any other response so they contribute to the unread count. - Add aria-label="Test response" to the inline Test badge in the dashboard From column so screen readers get a complete label. - Add two PHPUnit round-trip tests covering the JWT backward-compat contract: a JWT issued in preview mode marks the decoded form as a test submission; a JWT issued outside preview mode (or from a cached HTML fragment predating this feature) decodes to a regular submission. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d0486e4 to
b7623ff
Compare
- List view: move Test badge to end of the From row, switch to the neutral white badge, and show the form title (linked to preview) in the Source column instead of the Form Preview badge. - Detail panel: drop the standalone banner row, render the Test badge inline (right-aligned) next to name/email, and link the form title in the Source row. - Export modal: drop the bottom info notice, move the top notice above the content card, and tone it down from warning to info. - Email: replace the amber test-submission banner with a simple heading line above the feedback body.
Revert to surfacing "Form preview" (sentence case) as the Source label for test feedback in both the list Source column and the detail panel, linked to the regenerated preview URL when available.
Apply the same "Form preview" Source label + preview-URL link to the legacy DataViews inbox list so test responses surface consistently whether or not CFM is enabled.
Bring back the amber notice block at the top of test-submission emails, but drop the secondary explanatory sentence — just the "Test submission from form preview" heading now.
Pass the test-submission banner through wrap_message_in_html_tags as a new optional argument and render it above the white card in the email template, so the rest of the body still reads like a normal submission email.
Swap the banner copy from "Test submission from form preview" to "Test response via form preview" to match the terminology used in the dashboard.
Override the Source row in the notification email metadata table so test responses read as "Form preview" (no link), matching the dashboard treatment, instead of the hosting page URL.
Keep the original top-left alignment for the gravatar/name block in the single response header. The Test badge keeps itself vertically centered with alignSelf so test rows still look balanced.
Wrap the test-response notice in a spacer div so it doesn't butt up against the CSV export card below.
|
It's a bummer that injecting the badge into the name now doesn't allow filtering just tests to easily remove them. Any way around it? E.g. filtrable/sortable but without its own column? |
| > | ||
| <VStack spacing={ 8 }> | ||
| { selectedTestCount > 0 && ( | ||
| <div style={ { marginBottom: '24px' } }> |
There was a problem hiding this comment.
Wouldn't the VStack take care of the spacing if Notice would go inside it?
| */ | ||
| private static function build_test_submission_banner() { | ||
| return sprintf( | ||
| '<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%%" style="border-collapse: collapse; margin: 0 0 24px 0;"> |
There was a problem hiding this comment.
Let's use the modern notice styles here instead of the deprecated component?
Replace the planned separate "Response type" filter with a virtual "Form preview" option injected at the top of the existing Source filter. When selected, the source value "form_preview" is translated to is_test=true on the query. Keeps filtering UX to a single pill and avoids the extra filter chrome. Also exposes is_test on the feedback REST collection (GET /feedback) and stamps test submissions with the _feedback_is_test post meta on insert, so the filter can scope at the database level without unpacking the serialized source.
Move the "Test" badge out of a marginLeft:auto span and into a row next to the respondent name in both the response list and the single-response inspector. The auto-margin pushed the badge to the cell's far edge, which on narrow widths could overflow into the adjacent Date column.
Drop the 4px left-border accent in favor of the @wordpress/ui Notice
warning palette: 1px amber border, 8px radius, warm amber fill
(#fff7e0 / #d0b381), and 13px/20px body copy in #2e1900. Punctuate the
body copy ("Test response via form preview.") and add mobile-only side
margin so the banner aligns with the rest of the email content on
narrow viewports.
Also fold the export modal's test-response Notice into the same VStack
as the export options instead of wrapping it in a bespoke marginBottom
div, so the 24px spacing comes from the VStack like every other child.
Replace the legacy @wordpress/components Notice (status="info", isDismissible) with the @wordpress/ui Notice.Root + Notice.Description (intent="info") so the test-response warning in the Export responses modal matches the rest of the new WPDS-based surfaces.
The phpunit.11.xml.dist config sets failOnDeprecation="true", which on PHP 8.5 treats the ReflectionProperty::setAccessible() deprecation as a fatal signal — making the packages/forms test job exit non-zero even when every assertion passes. Pass --do-not-fail-on-deprecation to phpunit-select-config so the run succeeds on deprecation notices, and --display-deprecations so they still surface in the CI log for visibility.
Replace the composer-level --do-not-fail-on-deprecation / --display-deprecations workaround with a version-guarded call at the source. PHP 8.1 made setAccessible() a no-op for all reflection objects and PHP 8.5 deprecates calling it on ReflectionProperty, so on 8.1+ the package-supported branch now skips the call entirely. The 7.2–8.0 codepath still invokes setAccessible() so the test keeps working against the package's minimum PHP.
The guard is purely a test-only change (never ships to users), so it doesn't need a changelog entry.













Fixes FORMS-638
Proposed changes
?jetpack_form_preview=…previews have been replaced with a form-id-scoped nonce verification, so editors can submit the form to verify the entire pipeline (validation, success state, email delivery).Feedback_Source. When the submission comes from preview, the feedback is flagged via a newis_testfield onFeedback_Sourcethat travels inside the serialized v3 post content. Storage uses the normalpublishpost status — no new post status, no new post meta.jetpack_forms_send_test_feedback_emailfilter), the subject is prefixed with[TEST](filterable viajetpack_forms_test_subject_prefix), and the email body gets a prominent banner. The "Mark as spam" footer link is dropped for test entries.Testbadge (intent="informational") rendered before the respondent name.Form Previewbadge in place of the source URL.Testbadge as the first line above the respondent block, and the Source row renders aForm Previewlink to the regenerated preview URL.is_testandpreview_url. Schema gets two new read-only properties;prepare_item_for_response()populates them.preview_urlis generated viaForm_Preview::generate_preview_url()against the feedback's parent form id, only for test responses.Related product discussion/links
Does this pull request change what data or activity we track or use?
No. The new
is_testflag lives in the existing serialized feedback content; no new tables, no new tracks events, no new tracking surfaces. Notification emails go to the same recipients they always have.Testing instructions
jetpack_formdirectly).?jetpack_form_preview=<id>&preview_nonce=…. Confirm the banner now reads "This is a preview. Submissions are saved as test responses."[TEST]subject prefix and an amberTest submission from form previewbanner at the top of the body.Testbadge before the respondent name.Form Previewbadge instead of an external URL.Testbadge above the gravatar/name block, and the Source: row readsForm Previewlinked to the preview URL.jetpack_form_preview_nonce) and submit → expect the submission to be rejected.Dashboard:

Email:

Export modal (default)

Export modal (with test responses selected)
