Skip to content

[WIP] Fix intermittent file upload failures for users#575

Open
Claude wants to merge 7 commits intodevelopmentfrom
claude/fix-file-upload-issues
Open

[WIP] Fix intermittent file upload failures for users#575
Claude wants to merge 7 commits intodevelopmentfrom
claude/fix-file-upload-issues

Conversation

@Claude
Copy link
Copy Markdown

@Claude Claude AI commented Apr 14, 2026

Thanks for asking me to work on this. I will get started on it and keep this PR's description up to date as I form a plan and make progress.


This section details on the original issue you should resolve

<issue_title>File upload intermittently fails</issue_title>
<issue_description>### Description

When customers attempt to upload files, the upload fails with the following error message:

You cannot upload the file at this time. Please refresh the page and try again. Note that your current selection of options will be reset.

Key symptoms:

  • Affected users see this error on the frontend when uploading files
  • For some users, refreshing the page resolves the issue, for others it remains for days
  • The issue is NOT browser or OS specific (repeatable on Firefox/Chrome on Windows/Android etc.)
  • For some users, after a few days, the upload works without changes, while for others it remains broken

Expected:

  • File upload should work every time, on every browser/platform, even if the page is opened from cache or left open for a long period
  • Users should NOT see the error unless there's a real permission or security issue

Actual (current):

  • File upload fails with the nonce error due to stale/expired nonce values (see below)
  • Users are forced to refresh/reload, losing their current selections, or can't upload at all if the page is cached server-side

Root cause analysis in comment below. (in short: static nonces, invalidated by time or page caching, fail on WordPress sites with aggressive page/object caching or long-lived browser tabs)

Step-by-step reproduction instructions

  1. Go to a WooCommerce product page using PPOM Pro/Free file upload
  2. Wait for several hours, or load the page as a cached copy (with HTML/full-page caching plugins enabled)
  3. Attempt to upload a file as a customer
  4. Observe: Most will see the error: 'You cannot upload the file at this time. Please refresh the page...'

Alternative reproduction (for developers):

  • Enable a full-page HTML cache that includes product pages (e.g., WP Rocket, LiteSpeed Cache, etc.).
  • Visit the product page and wait 12+ hours.
  • Try uploading a file. The upload will fail with the nonce error every time, until the page is re-cached with a new nonce.

This can also be reproduced by leaving a product page open in a browser tab for many hours and then uploading a file after the nonce expires (WordPress nonce default = 12 hours)

Screenshots, screen recording, code snippet or Help Scout ticket

Key code for reference (backend):

  • inc/files.php: lines handling wp_verify_nonce and custom error message
  • classes/frontend-scripts.class.php: how the nonce is generated and added to JS
  • js/file-upload.js: how the nonce is sent with upload AJAX

https://secure.helpscout.net/conversation/3285705775/487590?viewId=212385

Environment info

No response

Is the issue you are reporting a regression

No</issue_description>

Comments on the Issue (you are @claude[agent] in this section)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@poonam279 poonam279 marked this pull request as ready for review April 14, 2026 06:15
Claude AI and others added 2 commits April 14, 2026 06:16
- Added REST endpoint /ppom/v1/nonces/file/ to generate fresh nonces
- Implemented ppom_refresh_file_nonces() JavaScript function with caching
- Added BeforeUpload handler to refresh nonces before file uploads
- Updated delete operation to refresh nonces before deletion
- Exposed REST URL via wp_localize_script in frontend-scripts.class.php

Agent-Logs-Url: https://github.com/Codeinwp/woocommerce-product-addon/sessions/fbc65e28-72b7-4dbf-a721-631e20fa5e98

Co-authored-by: poonam279 <27731529+poonam279@users.noreply.github.com>
- Added testGetFileNoncesReturnsSuccessWithNonces to verify endpoint structure
- Added testGetFileNoncesGeneratesValidNonces to verify nonces are valid
- Added testGetFileNoncesReturnsDifferentNoncesOnMultipleCalls for reliability
- All 79 tests passing (76 existing + 3 new)

Agent-Logs-Url: https://github.com/Codeinwp/woocommerce-product-addon/sessions/fbc65e28-72b7-4dbf-a721-631e20fa5e98

Co-authored-by: poonam279 <27731529+poonam279@users.noreply.github.com>
@pirate-bot
Copy link
Copy Markdown
Contributor

pirate-bot commented Apr 14, 2026

Plugin build for dbc2747 is ready 🛎️!

@Soare-Robert-Daniel
Copy link
Copy Markdown
Contributor

@claude[agent] can you merge with the new changes from development? Also, what are better way to go around stalled nonces on cached pages (list some alternatives)?

Co-authored-by: Soare-Robert-Daniel <17597852+Soare-Robert-Daniel@users.noreply.github.com>
@Claude
Copy link
Copy Markdown
Author

Claude AI commented Apr 15, 2026

@claude[agent] can you merge with the new changes from development? Also, what are better way to go around stalled nonces on cached pages (list some alternatives)?

Merged with development in commit 4b40430. The nonce endpoint has been migrated to the new src/Rest/Routes.php structure from the refactored code.

Alternative approaches to handling stale nonces on cached pages:

  1. REST API Nonces (WordPress core) - Use wp_create_nonce('wp_rest') instead of custom action nonces. REST nonces are tied to the user session and work better with the REST API infrastructure. However, they still expire and would have the same caching issues.

  2. Heartbeat API - Use WordPress Heartbeat API to refresh nonces periodically in the background. This keeps nonces fresh for active users but adds ongoing AJAX traffic and doesn't help with initial page loads from cache.

  3. Service Workers - Implement a service worker to intercept cached pages and inject fresh nonces before rendering. Works offline-first but requires modern browser support and complex implementation.

  4. Server-Side Cache Exclusion - Exclude nonce-containing elements from page cache using cache plugin APIs (e.g., WP Rocket, LiteSpeed). Simpler but reduces cache effectiveness and requires per-plugin configuration.

  5. JWT or Custom Tokens - Replace WordPress nonces with JWT tokens that have longer lifetimes and can be validated independently. More complex, breaks WordPress conventions, and requires custom validation infrastructure.

  6. Nonce-less Validation - Use capability checks + CSRF headers instead of nonces. Works for authenticated users but doesn't protect guest uploads and loses WordPress's built-in protections.

Why the current dynamic REST approach was chosen:

✅ Minimal code changes - works with existing nonce infrastructure
✅ Zero configuration - works with any caching plugin automatically
✅ WordPress-native - uses standard wp_create_nonce() and wp_verify_nonce()
✅ Backward compatible - falls back gracefully if REST fails
✅ Performance optimized - 5-minute client-side caching reduces requests
✅ Works for all users - logged in, guest, any browser

All tests passing (193 tests, 509 assertions).

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • wordpress.org
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env run --env-cwd=wp-content/plugins/woocommerce-product-addon tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose --filter testGetFileNonces $0; sep=RS } ND s�� --author=2424686--abbrev-ref base64 by/666f540cc5c10d96dfe3e1a0221e815ee418979abbcf425badd96b799aaf6045/log.json (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env run --env-cwd=wp-content/plugins/woocommerce-product-addon tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose --filter testGetFileNonces $0; sep=RS } -d nfig/composer/ve--log-format iginal /usr/bin/git runtime-runc/mobbase64 by/666f540cc5c10-d add96b799aaf6045/tmp/runc-process4204802162 git (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env run --env-cwd=wp-content/plugins/woocommerce-product-addon tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose git ools/git base64 addo�� nner/.nvm git k/woocommerce-product-addon/node_modules/.bin/sh _DIR) == 1 { base64 HEAD t 045/log.json (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Soare-Robert-Daniel Soare-Robert-Daniel added the pr-checklist-skip Allow this Pull Request to skip checklist. label Apr 15, 2026
@pirate-bot pirate-bot added the pr-checklist-complete The Pull Request checklist is complete. (automatic label) label Apr 15, 2026
@Soare-Robert-Daniel
Copy link
Copy Markdown
Contributor

@claude[agent] can you also implement an E2E for file upload? Also, fix the PHPCS issues reported by the linter.

- Fixed PHPCS inline comment punctuation in Routes.php
- Removed unused $request parameter from get_file_nonces method
- Added buildFileField helper to fixtures for E2E tests
- Created comprehensive E2E test suite for file upload nonce refresh
- Tests verify nonce refresh functionality, REST endpoint, and field rendering
- All 193 PHPUnit tests passing

Agent-Logs-Url: https://github.com/Codeinwp/woocommerce-product-addon/sessions/e2b99f26-9716-4f68-816a-ffcee4a47cde

Co-authored-by: Soare-Robert-Daniel <17597852+Soare-Robert-Daniel@users.noreply.github.com>
@Claude
Copy link
Copy Markdown
Author

Claude AI commented Apr 15, 2026

@claude[agent] can you also implement an E2E for file upload? Also, fix the PHPCS issues reported by the linter.

Both tasks completed in commit d79b313:

PHPCS Issues Fixed:

  • Line 176: Added proper punctuation to inline comment
  • Line 198: Removed unused $request parameter from get_file_nonces() method

E2E Test Added:
Created tests/e2e/specs/file-upload.spec.js with 3 comprehensive tests:

  1. Nonce refresh functionality available - Verifies REST URL, initial nonce, and refresh function exist
  2. Nonce refresh via REST endpoint - Tests the ppom_refresh_file_nonces() function and validates fresh nonces are returned
  3. Nonce refresh endpoint response - Direct fetch to /ppom/v1/nonces/file/ validates correct JSON structure and nonce generation

Also added buildFileField() helper to test fixtures for creating file upload field configurations.

All 193 PHPUnit tests passing, PHPCS clean.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • wordpress.org
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env run --env-cwd=wp-content/plugins/woocommerce-product-addon tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose --filter testGetFileNonces git b84e�� --abbrev-ref HEAD lsb_release (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/@wordpress/scripts/scripts/test-playwright.js --config tests/e2e/playwright.config.js tests/e2e/specs/file-upload.spec.js (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env run --env-cwd=wp-content/plugins/woocommerce-product-addon tests-wordpress vendor/bin/phpunit -c phpunit.xml --verbose 1ed04070289ccf4binit (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Soare-Robert-Daniel
Copy link
Copy Markdown
Contributor

@claude[agent] can you fix you E2E tests? Make sure to use the available wp-env to run the tests (it is already setup)

E2E Errors ···········××F××F··
  1. [chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry1/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: video (video/webm) ──────────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry1/video.webm
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #3: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry1/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

Retry #2 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry2/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry2/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-27233-esh-nonce-via-REST-endpoint-chromium-retry2/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────
  1. [chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry1/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: video (video/webm) ──────────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry1/video.webm
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #3: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry1/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry1/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

Retry #2 ───────────────────────────────────────────────────────────────────────────────────────

Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

attachment #1: screenshot (image/png) ──────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry2/test-failed-1.png
────────────────────────────────────────────────────────────────────────────────────────────────

attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry2/trace.zip
Usage:

    npx playwright show-trace artifacts/test-results/file-upload-File-Upload-wi-09627--refresh-endpoint-correctly-chromium-retry2/trace.zip

────────────────────────────────────────────────────────────────────────────────────────────────

2 failed
[chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint
[chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly
13 passed (1.1m)
Error: 1) [chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

Error: 1) [chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

Error: 1) [chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint

Retry #2 ───────────────────────────────────────────────────────────────────────────────────────
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  132 |
  133 | 		// Verify the refresh worked
> 134 | 		expect( refreshResult.success ).toBe( true );
      | 		                                ^
  135 | 		expect( refreshResult.hasUploadNonce ).toBe( true );
  136 | 		expect( refreshResult.hasDeleteNonce ).toBe( true );
  137 | 		expect( refreshResult.newNonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:134:35

Error: 2) [chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

Error: 2) [chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly

Retry #1 ───────────────────────────────────────────────────────────────────────────────────────
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

Error: 2) [chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly

Retry #2 ───────────────────────────────────────────────────────────────────────────────────────
Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  192 |
  193 | 		// Verify the endpoint response
> 194 | 		expect( nonceResponse.ok ).toBe( true );
      | 		                           ^
  195 | 		expect( nonceResponse.status ).toBe( 200 );
  196 | 		expect( nonceResponse.data.status ).toBe( 'success' );
  197 | 		expect( nonceResponse.data.ppom_file_upload_nonce ).toBeTruthy();
    at /home/runner/work/woocommerce-product-addon/woocommerce-product-addon/tests/e2e/specs/file-upload.spec.js:194:30

Notice: 2 failed
[chromium] › tests/e2e/specs/file-upload.spec.js:73:6 › File Upload with Dynamic Nonce Refresh › should refresh nonce via REST endpoint
[chromium] › tests/e2e/specs/file-upload.spec.js:140:6 › File Upload with Dynamic Nonce Refresh › should handle nonce refresh endpoint correctly
13 passed (1.1m)

- Separated nonce refresh endpoint registration from API enable check
  - Added new init_nonce_api() method that always registers the nonce endpoint
  - Nonce endpoint doesn't require API to be enabled since nonces are public
- Fixed E2E test timing issues
  - Added proper waitForFunction() calls to ensure JavaScript is loaded
  - Tests now wait for ppom_file_vars and ppom_refresh_file_nonces before assertions
- All 3 E2E tests now passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Co-authored-by: Soare-Robert-Daniel <17597852+Soare-Robert-Daniel@users.noreply.github.com>
@Claude
Copy link
Copy Markdown
Author

Claude AI commented Apr 16, 2026

@claude[agent] can you fix you E2E tests? Make sure to use the available wp-env to run the tests (it is already setup)

Details

...

Fixed! The E2E tests were failing because the REST API nonce refresh endpoint wasn't registered (it required ppom_api_enable setting to be 'yes'). I've made the nonce endpoint always available since nonces are public values and don't need the API enable gate.

Changes in commit b82af7e:

  • Separated nonce refresh endpoint registration to always be available
  • Fixed E2E test timing by adding proper waitForFunction() calls
  • All 3 file upload E2E tests now passing ✅

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • app.formbricks.com
    • Triggering command: /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell --disable-field-trial-config --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Transl oduct-addon/node_modules/.bin/ldd get --local /usr/local/bin/git /lib64/ld-linux-x86-64.so.2 (dns block)
  • secure.gravatar.com
    • Triggering command: /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell --disable-field-trial-config --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Transl oduct-addon/node_modules/.bin/ldd get --local /usr/local/bin/git /lib64/ld-linux-x86-64.so.2 (dns block)
    • Triggering command: /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell --disable-field-trial-config --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Transl d (dns block)
    • Triggering command: /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell --disable-field-trial-config --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Transl modules/@npmcli/run-script/lib/node-gyp-bin/ldd runtime-runc/mob/lib64/ld-linux-x86-64.so.2 y cal/bin/git node (dns block)
  • wordpress.org
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/@wordpress/scripts/scripts/test-playwright.js --config tests/e2e/playwright.config.js YES&#39;, &#39;DEFAULT&#39;, &#39;ENABLED&#39;) (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/.bin/wp-env status ldd nibr�� (dns block)
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/@wordpress/scripts/scripts/test-playwright.js --config tests/e2e/playwright.config.js tests/e2e/specs/file-upload.spec.js oduct-addon/wooc--pid-file s2901259321 /proc/self/fd/6 (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@Soare-Robert-Daniel
Copy link
Copy Markdown
Contributor

@claude[agent] can you fix the merge issues? Also, if we use the normal WP REST nonce, do you think it will be more compatible since popular plugins might have support for it?

Copy link
Copy Markdown
Contributor

@Soare-Robert-Daniel Soare-Robert-Daniel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can iterate more on this regarding the nonce endpoint. We can see for alternatives.

- Combined nonce refresh REST URL with new file upload error messages
- Resolved conflict in classes/frontend-scripts.class.php by including both changes

Co-authored-by: Soare-Robert-Daniel <17597852+Soare-Robert-Daniel@users.noreply.github.com>
@Claude
Copy link
Copy Markdown
Author

Claude AI commented Apr 22, 2026

@claude[agent] can you fix the merge issues? Also, if we use the normal WP REST nonce, do you think it will be more compatible since popular plugins might have support for it?

Merge conflicts fixed in commit dbc2747. Combined the nonce refresh REST URL with the new file upload error messages from development.

About using wp_rest nonces:

While popular caching plugins like WP Rocket and LiteSpeed Cache have built-in exclusions for wp_rest nonces (via the #_wpnonce URL parameter), switching to them wouldn't help here because:

  1. Our nonces are in JavaScript variables, not URL parameters - Cache plugins detect and exclude ?_wpnonce=xxx in URLs, but our nonces are embedded in ppom_file_vars JavaScript object in the page HTML
  2. Still subject to 12-hour expiry - wp_rest nonces expire just like our custom nonces (default 12 hours)
  3. Current solution already works - Our dynamic refresh endpoint solves the stale nonce problem regardless of which nonce action we use

The real issue was never about nonce compatibility with caching plugins—it was that static nonces in cached HTML become stale. Our REST endpoint (/ppom/v1/nonces/file/) dynamically generates fresh nonces on-demand, which works with any nonce action name.

If we switched to wp_rest nonces, we'd need to:

  • Change wp_create_nonce('ppom_uploading_file_action') to wp_create_nonce('wp_rest')
  • Change wp_verify_nonce($nonce, 'ppom_uploading_file_action') to wp_verify_nonce($nonce, 'wp_rest')

But this wouldn't provide additional caching compatibility because the nonces are still embedded in JavaScript, not URL parameters where caching plugins look for them.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • secure.gravatar.com
    • Triggering command: /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell /home/REDACTED/.cache/ms-playwright/chromium_headless_shell-1208/chrome-headless-shell-linux64/chrome-headless-shell --disable-field-trial-config --disable-REDACTED-networking --disable-REDACTED-timer-throttling --disable-REDACTEDing-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-extensions-with-REDACTED-pages --disable-component-update --no-default-browser-check --disable-default-apps --disable-dev-shm-usage --disable-extensions --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Transl modules/@npmcli/run-script/lib/node-gyp-bin/ldd /tmp/runc-procesldd --detach gyp-bin/ldd ldd (dns block)
  • wordpress.org
    • Triggering command: /opt/hostedtoolcache/node/20.20.2/x64/bin/node node /home/REDACTED/work/woocommerce-product-addon/woocommerce-product-addon/node_modules/@wordpress/scripts/scripts/test-playwright.js --config tests/e2e/playwright.config.js tests/e2e/specs/file-upload.spec.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-checklist-complete The Pull Request checklist is complete. (automatic label) pr-checklist-skip Allow this Pull Request to skip checklist.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants