playwright icon indicating copy to clipboard operation
playwright copied to clipboard

[Bug]: await response.json fails in Firefox with "SyntaxError: Unexpected end of JSON input"

Open sarah-gelt opened this issue 6 months ago • 2 comments

Version

1.53.1

Steps to reproduce

  1. Use await page.waitForResponse() to capture a response received by the browser
  2. Attempt to access the response body with const json = await response.json()
  3. Run the test in Firefox

Snippet of our actual test:

const [response] = await Promise.all([
   page.waitForResponse("**/doc-vault/files*"),
   fileChooser.setFiles(path.join(__dirname, "../_assets/gelt2.jpg"))
]);
const responseBody = await response.json();

Generic test example:

test("Testing", async ({ context }) => {
    const newPage = await context.newPage();
    const [response] = await Promise.all([
      newPage.waitForResponse("https://play.google.com/**"),
      newPage.goto("https://www.google.com")
    ]);
    const json = await response.json();
    console.log(json);
    await newPage.close();
  });

Expected behavior

The JSON body is available to use in the rest of the test

Actual behavior

Test fails with

SyntaxError: Unexpected end of JSON input

  621 |           fileChooser.setFiles(path.join(__dirname, "../_assets/gelt2.jpg"))
  622 |         ]);
> 623 |         const responseBody = await response.json();

Additional context

The code has been unchanged for a year or more and has always worked in all browsers we test with (Chrome, Webkit, Firefox). Since upgrading away from 1.51, all tests using response.json() fail in Firefox.

Environment

System:
    OS: macOS 15.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 191.94 MB / 16.00 GB
  Binaries:
    Node: 22.14.0 - ~/.nvm/versions/node/v22.14.0/bin/node
    npm: 10.9.2 - ~/.nvm/versions/node/v22.14.0/bin/npm
    pnpm: 10.7.1 - ~/.nvm/versions/node/v22.14.0/bin/pnpm
  IDEs:
    VSCode: 1.101.1 - /usr/local/bin/code
  Languages:
    Bash: 3.2.57 - /bin/bash
  npmPackages:
    @playwright/test: 1.53.1 => 1.53.1 
    playwright-qase-reporter: ^1.2.0-alpha.3 => v1.2.2

sarah-gelt avatar Jun 24 '25 13:06 sarah-gelt

Could you try calling await response.text() instead and post the body here? The error code says that the response doesn't contain valid JSON.

Skn0tt avatar Jun 24 '25 13:06 Skn0tt

The response text is empty with Firefox. If I run the same test with Chrome instead, I can get both response text and json successfully.

Chrome - text & json: Image

Text:

"[\"-1\",null,[[[\"ANDROID_BACKUP\",0],[\"BATTERY_STATS\",0],[\"SMART_SETUP\",0],[\"TRON\",0]],-3334737594024971225],[],{\"175237375\":[10000]}]"

JSON:

[
  "-1",
  null,
  [
    [
      [
        "ANDROID_BACKUP",
        0,
      ],
      [
        "BATTERY_STATS",
        0,
      ],
      [
        "SMART_SETUP",
        0,
      ],
      [
        "TRON",
        0,
      ],
    ],
    -3334737594024971300,
  ],
  [
  ],
  {
    "175237375": [
      10000,
    ],
  },
]

Firefox - text empty string: Image

Firefox - fails on json Image

sarah-gelt avatar Jun 24 '25 13:06 sarah-gelt

I see. So the "Unexpected end of JSON input" error is correct - an empty string isn't valid JSON. To me, this looks like Google Play is just sending back an empty response for this request on this new version of Firefox. Maybe it's a HTTP redirect? Try investigating response headers and response status code, that should lead you somewhere.

Skn0tt avatar Jun 24 '25 14:06 Skn0tt

From the response in code:

status: 200
headers:
{
  "access-control-allow-origin": "https://www.google.com",
  "access-control-allow-methods": "GET, POST, OPTIONS",
  "access-control-max-age": "86400",
  "access-control-allow-credentials": "true",
  "access-control-allow-headers": "X-Playlog-Web, authorization, content-encoding, content-type, origin",
  "content-type": "text/plain; charset=UTF-8",
  date: "Tue, 24 Jun 2025 14:27:28 GMT",
  server: "Playlog",
  "content-length": "0",
  "x-xss-protection": "0",
  "x-frame-options": "SAMEORIGIN",
  "alt-svc": "h3=\":443\"; ma=2592000, h3-29=\":443\"; ma=2592000",
  "x-firefox-spdy": "h2",
}

From the response in Firefox when the test is running. Note that content-length in PW is 0 but in Firefox it is 131:

Image

And Firefox has the JSON response as expected:

Image

sarah-gelt avatar Jun 24 '25 14:06 sarah-gelt

The headers you posted look like the response to a CORS preflight request. Could you check the response's request method? response.request().method is probably OPTIONS.

Skn0tt avatar Jun 24 '25 14:06 Skn0tt

Bingo! If I specify the method I want then I always get the actual request response I'm looking for rather than the preflight 👍 I might tweak this to be !== OPTIONS before I commit anything, more testing needed first.

Tried this in one of our actual tests with great success:

page.waitForResponse((response) =>
   RegExp(/^.*\/doc-vault\/files.*$/).exec(response.url()) !== null &&
   response.request().method() === "POST"
)

I don't know why Firefox is only now returning the preflight request's response where it didn't before, and none of the other browsers do 🤔 It makes sense when you think about it because the preflight happens first, so perhaps we've just been lucky for the last 2-3 years 😅

sarah-gelt avatar Jun 24 '25 14:06 sarah-gelt

Good to hear we got to the bottom of this! This is probably caused by some upstream Firefox change 🤷

Skn0tt avatar Jun 24 '25 15:06 Skn0tt