Skip to content

[Bug] codegen serializedArgs can be of type string (should be object) perhaps caused by backward compat bug #21786

@chrisjsimpson

Description

@chrisjsimpson

Background: Working with an ancient hardware embedded web ui (circa 2012) which uses the prototypejs framework.

Playwright version

npx playwright --version
Version 1.31.2

Test case (happy path)

npx playwright codegen http://127.0.0.1:

<!DOCTYPE html>
<html>
	<head></head>
	<body>
		<form>
			Name <input type="text" name="name" />
			<input type="submit" />
		</form>
	</body>
</html>

Produces the following events:

What I'm doing is clicking the <input type="text" name="name" /> and typing the word 'test' into that form control.
This is working as expected:

serializedArgs is type object
[{"o":[{"k":"name","v":"click"},{"k":"selector","v":"internal:role=textbox"},{"k":"position","v":{"v":"undefined"}},{"k":"signals","v":{"a":[],"id":2}},{"k":"button","v":"left"},{"k":"modifiers","v":0},{"k":"clickCount","v":1}],"id":1}]
args
args is type object
[
  {
    name: 'click',
    selector: 'internal:role=textbox',
    position: undefined,
    signals: [],
    button: 'left',
    modifiers: 0,
    clickCount: 1
  }
]
ok
serializedArgs
serializedArgs is type object
[]
args
args is type object
[]
ok
serializedArgs
serializedArgs is type object
[]
args
args is type object
[]
ok
serializedArgs
serializedArgs is type object
[{"o":[{"k":"name","v":"fill"},{"k":"selector","v":"internal:role=textbox"},{"k":"signals","v":{"a":[],"id":2}},{"k":"text","v":"t"}],"id":1}]
args
args is type object
[
  {
    name: 'fill',
    selector: 'internal:role=textbox',
    signals: [],
    text: 't'
  }
]
ok
serializedArgs
serializedArgs is type object
[{"o":[{"k":"name","v":"fill"},{"k":"selector","v":"internal:role=textbox"},{"k":"signals","v":{"a":[],"id":2}},{"k":"text","v":"te"}],"id":1}]
args
args is type object
[
  {
    name: 'fill',
    selector: 'internal:role=textbox',
    signals: [],
    text: 'te'
  }
]
ok
serializedArgs
serializedArgs is type object
[{"o":[{"k":"name","v":"fill"},{"k":"selector","v":"internal:role=textbox"},{"k":"signals","v":{"a":[],"id":2}},{"k":"text","v":"tes"}],"id":1}]
args
args is type object
[
  {
    name: 'fill',
    selector: 'internal:role=textbox',
    signals: [],
    text: 'tes'
  }
]
ok
serializedArgs
serializedArgs is type object
[{"o":[{"k":"name","v":"fill"},{"k":"selector","v":"internal:role=textbox"},{"k":"signals","v":{"a":[],"id":2}},{"k":"text","v":"test"}],"id":1}]
args
args is type object
[
  {
    name: 'fill',
    selector: 'internal:role=textbox',
    signals: [],
    text: 'test'
  }
]
ok
serializedArgs
serializedArgs is type object
[]
args
args is type object
[]
ok

Sad path with prototypejs: serializedArgs can be of type string (should be object)

Please note I have not pasted in the prototypejs application, apologies.

When clicking or entering (any event) playwright page.js throws the following, because for some reason (quirks mode type thing? I don't know) causes serializedArgs to be of string type:

Uncaught (in promise) TypeError: serializedArgs.map is not a function
    at Function.dispatch node_modules/playwright-core/lib/server/page.js:609:37)
    at Page._onBindingCalled (node_modules/playwright-core/lib/server/page.js:218:23)
    at FrameSession._onBindingCalled (node_modules/playwright-core/lib/server/chromium/crPage.js:717:37)

Event log: Here I also type the word test but into a different (much older) prototype application embeded in hardware:

Notice that serializedArgs is a string but should be an object.

npx playwright codegen http://192.168.1.1:

serializedArgs
serializedArgs is type string
"[]"
[]
ok
serializedArgs
serializedArgs is type string
"[{\"o\": [{\"k\": \"name\", \"v\": \"click\"}, {\"k\": \"selector\", \"v\": \"#user\"}, {\"k\": \"position\", \"v\": {\"v\": \"undefined\"}}, {\"k\": \"signals\", \"v\": {\"a\": [], \"id\": 2}}, {\"k\": \"button\", \"v\": \"left\"}, {\"k\": \"modifiers\", \"v\": 0}, {\"k\": \"clickCount\", \"v\": 1}], \"id\": 1}]"
[{"o": [{"k": "name", "v": "click"}, {"k": "selector", "v": "#user"}, {"k": "position", "v": {"v": "undefined"}}, {"k": "signals", "v": {"a": [], "id": 2}}, {"k": "button", "v": "left"}, {"k": "modifiers", "v": 0}, {"k": "clickCount", "v": 1}], "id": 1}]
ok
serializedArgs
serializedArgs is type string
"[]"
[]
ok
serializedArgs
serializedArgs is type string
"[{\"o\": [{\"k\": \"name\", \"v\": \"fill\"}, {\"k\": \"selector\", \"v\": \"#user\"}, {\"k\": \"signals\", \"v\": {\"a\": [], \"id\": 2}}, {\"k\": \"text\", \"v\": \"t\"}], \"id\": 1}]"
[{"o": [{"k": "name", "v": "fill"}, {"k": "selector", "v": "#user"}, {"k": "signals", "v": {"a": [], "id": 2}}, {"k": "text", "v": "t"}], "id": 1}]
ok
serializedArgs
serializedArgs is type string
"[{\"o\": [{\"k\": \"name\", \"v\": \"fill\"}, {\"k\": \"selector\", \"v\": \"#user\"}, {\"k\": \"signals\", \"v\": {\"a\": [], \"id\": 2}}, {\"k\": \"text\", \"v\": \"te\"}], \"id\": 1}]"
[{"o": [{"k": "name", "v": "fill"}, {"k": "selector", "v": "#user"}, {"k": "signals", "v": {"a": [], "id": 2}}, {"k": "text", "v": "te"}], "id": 1}]
ok
serializedArgs
serializedArgs is type string
"[]"
[]
ok
serializedArgs
serializedArgs is type string
"[{\"o\": [{\"k\": \"name\", \"v\": \"fill\"}, {\"k\": \"selector\", \"v\": \"#user\"}, {\"k\": \"signals\", \"v\": {\"a\": [], \"id\": 2}}, {\"k\": \"text\", \"v\": \"tes\"}], \"id\": 1}]"
[{"o": [{"k": "name", "v": "fill"}, {"k": "selector", "v": "#user"}, {"k": "signals", "v": {"a": [], "id": 2}}, {"k": "text", "v": "tes"}], "id": 1}]
ok
serializedArgs
serializedArgs is type string
"[{\"o\": [{\"k\": \"name\", \"v\": \"fill\"}, {\"k\": \"selector\", \"v\": \"#user\"}, {\"k\": \"signals\", \"v\": {\"a\": [], \"id\": 2}}, {\"k\": \"text\", \"v\": \"test\"}], \"id\": 1}]"
[{"o": [{"k": "name", "v": "fill"}, {"k": "selector", "v": "#user"}, {"k": "signals", "v": {"a": [], "id": 2}}, {"k": "text", "v": "test"}], "id": 1}]
ok
serializedArgs
serializedArgs is type string

The crude 'fix' in playwright-core/lib/server/page.js

tldr JSON.parse serializedArgs to an object. (but why has serializedArgs become a string?).

  • change serializedArgs from const to mutable
  • serializedArgs = JSON.parse(serializedArgs); to an object
  static async dispatch(page, payload, context) {
    let {
      name,
      seq,
      serializedArgs
    } = JSON.parse(payload);
    try {
      (0, _utils.assert)(context.world);
      const binding = page.getBinding(name);
      let result;
      if (binding.needsHandle) {
        const handle = await context.evaluateHandle(takeHandle, {
          name,
          seq
        }).catch(e => null);
        result = await binding.playwrightFunction({
          frame: context.frame,
          page,
          context: page._browserContext
        }, handle);
      } else {
        console.log("ok");
        console.log("serializedArgs");
        console.log("serializedArgs is type", typeof(serializedArgs));
        console.log(JSON.stringify(serializedArgs));
        if ( typeof(serializedArgs) === 'string' ) {
          console.log("Converting serializedArgs into an object")

          try {
            serializedArgs = JSON.parse(serializedArgs);
            console.log(serializedArgs);
          } catch (e) {
            console.error("Unable to parse serializedArgs:", e);
          }
          console.log(serializedArgs);
        }
        debugger;

I hope that helps, appreciate this is a very niche usecase however took me a long time to root cause so someone else may benefit if they're hitting this

  • are we hitting some background compatibility /pollyfills perhaps?
  • I've not been able to identify why / when serializedArgs gets stringified

p.s. I would appreciate if someone would direct me how to use debugger; & --inspect --debug-brk within the context of playwright codegen it would save a lot of time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions