/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Check evaluating getters on prototype nodes in the console.
const TEST_URI = "data:text/html;charset=utf8,<h1>Object Inspector on Getters</h1>";

add_task(async function() {
  const hud = await openNewTabAndConsole(TEST_URI);

  await ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
    class A {
      constructor() {
        this.myValue = "foo";
      }
      get value() {
        return `A-value:${this.myValue}`;
      }
    }

    class B extends A {
      get value() {
        return `B-value:${this.myValue}`;
      }
    }

    class C extends A {
      constructor() {
        super();
        this.myValue = "bar";
      }
    }

    const a = new A();
    const b = new B();
    const c = new C();

    const d = new C();
    d.myValue = "d";

    content.wrappedJSObject.console.log("oi-test", a, b, c, d);
  });

  const node = await waitFor(() => findMessage(hud, "oi-test"));
  const [a, b, c, d] = node.querySelectorAll(".tree");

  await testObject(a, {
    myValue: `myValue: "foo"`,
    value: `value: "A-value:foo"`,
  });

  await testObject(b, {
    myValue: `myValue: "foo"`,
    value: `value: "B-value:foo"`,
  });

  await testObject(c, {
    myValue: `myValue: "bar"`,
    value: `value: "A-value:bar"`,
  });

  await testObject(d, {
    myValue: `myValue: "d"`,
    value: `value: "A-value:d"`,
  });
});

async function testObject(oi, {myValue, value}) {
  expandObjectInspectorNode(oi.querySelector(".tree-node"));
  const prototypeNode = await waitFor(() => findObjectInspectorNode(oi, "<prototype>"));
  let valueGetterNode = await getValueNode(prototypeNode);

  ok(findObjectInspectorNode(oi, "myValue").textContent.includes(myValue),
    `myValue has expected "${myValue}" content`);

  getObjectInspectorInvokeGetterButton(valueGetterNode).click();

  await waitFor(() =>
    !getObjectInspectorInvokeGetterButton(findObjectInspectorNode(oi, "value")));
  valueGetterNode = findObjectInspectorNode(oi, "value");
  ok(valueGetterNode.textContent.includes(value),
    `Getter now has the expected "${value}" content`);
}

async function getValueNode(prototypeNode) {
  expandObjectInspectorNode(prototypeNode);

  await waitFor(() => getObjectInspectorChildrenNodes(prototypeNode).length > 0);

  const children = getObjectInspectorChildrenNodes(prototypeNode);
  const valueNode = children.find(
    child => child.querySelector(".object-label").textContent === "value");

  if (valueNode) {
    return valueNode;
  }

  const childPrototypeNode = children.find(child =>
    child.querySelector(".object-label").textContent === "<prototype>");
  if (!childPrototypeNode) {
    return null;
  }

  return getValueNode(childPrototypeNode);
}

