import {
  getGeneVariantTw,
  getGenesetMutTw,
  getScctTw,
  getScgeneexpTw,
  getSsgseaTw
} from "./chunk-7FACFCZK.js";
import {
  Locator,
  detectAttr,
  detectChildAttr,
  detectChildStyle,
  detectGte,
  detectLst,
  detectStyle,
  sleep
} from "./chunk-DJQTUDJM.js";
import {
  getRunPp,
  rideInit
} from "./chunk-W55XSG6K.js";
import {
  require_tape
} from "./chunk-QWOE5YTB.js";
import "./chunk-74ZU4BT6.js";
import "./chunk-IW57W7EQ.js";
import "./chunk-ZTYNN6G5.js";
import "./chunk-DKVUOBIE.js";
import "./chunk-PRZWSBMA.js";
import "./chunk-LTOBEUM2.js";
import "./chunk-MKAF2BHB.js";
import "./chunk-WKNI3HRQ.js";
import "./chunk-VGYTAYFK.js";
import "./chunk-67DBIM6H.js";
import {
  getSamplelstTW,
  openPlot,
  openSummaryPlot
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import "./chunk-HYOEWQ5P.js";
import "./chunk-HBW42TDT.js";
import "./chunk-G6O3URDN.js";
import "./chunk-FN5XPUPH.js";
import "./chunk-IIT367QZ.js";
import "./chunk-RZGEKL77.js";
import "./chunk-UI7OCM2A.js";
import "./chunk-YZK37YCC.js";
import "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import {
  mclass
} from "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import "./chunk-KSGA62R2.js";
import "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import {
  select_default
} from "./chunk-I6Y4O3RR.js";
import {
  rgb
} from "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import {
  __toESM
} from "./chunk-HFNDKYVF.js";

// plots/scatter/test/scatter.integration.spec.js
var import_tape = __toESM(require_tape(), 1);
var runpp = getRunPp("mass", {
  state: {
    nav: { activeTab: 1 },
    vocab: {
      dslabel: "TermdbTest",
      genome: "hg38-test"
    }
  },
  debug: 1
});
var state = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      name: "TermdbTest TSNE"
    }
  ]
};
var open_state = {
  nav: { header_mode: "hide_search" },
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      name: "TermdbTest TSNE"
    }
  ]
};
var state3D = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      name: "TermdbTest TSNE",
      term0: { id: "agedx", q: { mode: "continuous" } }
    }
  ]
};
var stateDynamicScatter = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      term: { id: "agedx", q: { mode: "continuous" } },
      term2: { id: "hrtavg", q: { mode: "continuous" } }
    }
  ]
};
var state2geneexp = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      term: { term: { type: "geneExpression", gene: "AKT1" }, q: { mode: "continuous" } },
      term2: { term: { type: "geneExpression", gene: "TP53" }, q: { mode: "continuous" } }
    }
  ]
};
var state2ssgsea = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      term: { term: { type: "ssGSEA", id: "HALLMARK_ADIPOGENESIS" }, q: { mode: "continuous" } },
      term2: { term: { type: "ssGSEA", id: "HALLMARK_ALLOGRAFT_REJECTION" }, q: { mode: "continuous" } }
    }
  ]
};
var state2dnameth = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      term: {
        term: { type: "dnaMethylation", chr: "chr17", start: 7673484, stop: 7681953, genomicFeatureType: "gene" },
        q: { mode: "continuous" }
      },
      term2: {
        term: { type: "dnaMethylation", chr: "chr17", start: 7663195, stop: 7671664, genomicFeatureType: "gene" },
        q: { mode: "continuous" }
      }
    }
  ]
};
var state2scgeneexp = {
  plots: [
    {
      chartType: "sampleScatter",
      term: getScgeneexpTw(),
      term2: getScgeneexpTw("TP53")
    }
  ]
};
var state3DContour = {
  plots: [
    {
      chartType: "sampleScatter",
      colorTW: { id: "diaggrp" },
      name: "TermdbTest TSNE",
      term0: { id: "agedx", q: { mode: "continuous" } },
      settings: { sampleScatter: { showContour: true } }
    }
  ]
};
var groups = [
  {
    name: "Test group 1",
    items: [
      {
        sample: "2646",
        x: -103.141543,
        y: 73.31223702,
        sampleId: 41,
        category_info: {},
        hidden: {
          category: false
        },
        category: '"Acute lymphoblastic leukemia"',
        shape: "Ref"
      },
      {
        sample: "2800",
        x: -99.20065673,
        y: 73.64971694,
        sampleId: 52,
        category_info: {},
        hidden: {
          category: false
        },
        category: '"Acute lymphoblastic leukemia"',
        shape: "Ref"
      }
    ],
    index: 1
  }
];
function getHolder() {
  return select_default("body").append("div");
}
(0, import_tape.default)("\n", function(test) {
  test.comment("-***- plots/sampleScatter -***-");
  test.end();
});
(0, import_tape.default)("Render TermdbTest scatter plot and open survival and summary", function(test) {
  test.timeoutAfter(8e3);
  test.plan(7);
  const holder = getHolder();
  runpp({
    holder,
    //Fix for test failing because survival & summary sandboxs are not destroyed.
    state,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    const scatterDiv = scatter.Inner.model.charts[0].chartDiv;
    testPlot();
    testLegendTitle();
    const group = await testCreateGroup();
    const tw = getSamplelstTW([group]);
    await testOpenSurvivalPlot();
    await testOpenSummaryPlot();
    if (test._ok) holder.remove();
    test.end();
    function testPlot() {
      const serieG = scatterDiv.select(".sjpcb-scatter-series");
      const numSymbols = serieG.selectAll("path").size();
      test.equal(
        numSymbols,
        scatter.Inner.model.charts[0].data.samples.length,
        `Should be ${scatter.Inner.model.charts[0].data.samples.length}. Rendered ${numSymbols} symbols.`
      );
    }
    function testLegendTitle() {
      const g = scatterDiv.select(".sjpcb-scatter-legend");
      test.true(g != null, "Should have a legend");
      const texts = g.selectAll('text[data-testid="legendTitle"]');
      test.true(
        texts._groups[0][0].innerHTML.startsWith(scatter.Inner.config.colorTW.term.name),
        "colorTW legend title made"
      );
      test.true(
        texts._groups[0][1].innerHTML.startsWith(scatter.Inner.config.shapeTW.term.name),
        "shapeTW legend title made"
      );
    }
    async function testCreateGroup() {
      const samples = scatterDiv.select(".sjpcb-scatter-series").selectAll("path").nodes().filter((p) => p.__data__?.category === "Acute lymphoblastic leukemia").map((path) => path.__data__);
      test.equal(samples.length, 36, `Group should have 36 symbols.`);
      const self = scatter.Inner;
      const group2 = {
        name: `Group 1`,
        items: samples,
        index: 0
      };
      self.config.groups.push(group2);
      return group2;
    }
    async function testOpenSurvivalPlot() {
      const plots = scatter.Inner.app.getState().plots;
      const elem = scatter.Inner.app.Inner.dom.plotDiv.node();
      const preSandboxes = [...elem.querySelectorAll(".sjpp-sandbox")];
      const sandboxes = await detectLst({
        elem,
        selector: ".sjpp-sandbox",
        count: plots.length + 1,
        async trigger() {
          const survivalTerm = await scatter.Inner.app.vocabApi.getterm("efs");
          await openPlot("survival", survivalTerm, tw, scatter.Inner.app);
        }
      });
      const newSandbox = sandboxes.find((s) => !preSandboxes.includes(s));
      test.equal(
        [...newSandbox.querySelectorAll(".sja_errorbar")].filter((b) => b.style.display != "none").length,
        0,
        'Should render survival plot without errors".'
      );
    }
    async function testOpenSummaryPlot() {
      const plots = scatter.Inner.app.getState().plots;
      const elem = scatter.Inner.app.Inner.dom.plotDiv.node();
      const preSandboxes = [...elem.querySelectorAll(".sjpp-sandbox")];
      const survivalTerm = await scatter.Inner.app.vocabApi.getterm("efs");
      const sandboxes = await detectLst({
        elem,
        selector: ".sjpp-sandbox",
        count: plots.length + 1,
        async trigger() {
          const genderTerm = await scatter.Inner.app.vocabApi.getterm("sex");
          await openSummaryPlot(genderTerm, tw, scatter.Inner.app);
        }
      });
      const newSandbox = sandboxes.find((s) => !preSandboxes.includes(s));
      test.equal(
        [...newSandbox.querySelectorAll(".sja_errorbar")].filter((b) => b.style.display != "none").length,
        0,
        'Should render summary plot without errors".'
      );
    }
  }
});
(0, import_tape.default)("Render TermdbTest scatter plot adding age as Z to render a 3D plot", function(test) {
  test.timeoutAfter(8e3);
  test.plan(1);
  const holder = getHolder();
  runpp({
    holder,
    //Fix for test failing because survival & summary sandboxs are not destroyed.
    state: state3D,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    const is3D = scatter.Inner.model.is3D;
    const scatterDiv = scatter.Inner.model.charts[0].chartDiv;
    test.true(is3D, "Should be a 3D scatter plot");
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("Render 3D plot with age as Z and showContour set to true to apply contour on 3D plot", function(test) {
  test.timeoutAfter(8e3);
  test.plan(1);
  const holder = getHolder();
  runpp({
    holder,
    //Fix for test failing because survival & summary sandboxs are not destroyed.
    state: state3DContour,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    const chart = scatter.Inner.model.charts[0];
    await sleep(1e3);
    test.true(chart.plane != null, "Should have a plane with the contour map");
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("dynamic scatter of agedx & hrtavg", function(test) {
  test.timeoutAfter(8e3);
  test.plan(2);
  const holder = getHolder();
  runpp({
    holder,
    state: stateDynamicScatter,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const chart = scatter.Inner.model.charts[0];
    test.true(scatter.Inner.settings.showAxes, "Dynamic scatter should have axes");
    scatter.Inner.settings.showContour = true;
    await scatter.Inner.app.dispatch({
      type: "plot_edit",
      id: scatter.Inner.id,
      config: { settings: { sampleScatter: scatter.Inner.settings } }
    });
    const contourG = scatter.Inner.model.charts[0].chartDiv.select('g[stroke-linejoin="round"]').node();
    test.true(
      contourG != null,
      "Scatter should have contour showing the density of points after selecting show contour"
    );
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("dynamic scatter of 2-gene expression", function(test) {
  const holder = getHolder();
  runpp({
    holder,
    state: state2geneexp,
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const chart = scatter.Inner.model.charts[0];
    test.true(scatter.Inner.settings.showAxes, "Dynamic scatter should have axes");
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("dynamic scatter of 2-ssgsea", function(test) {
  const holder = getHolder();
  runpp({
    holder,
    state: state2ssgsea,
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const chart = scatter.Inner.model.charts[0];
    test.true(scatter.Inner.settings.showAxes, "Dynamic scatter should have axes");
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("dynamic scatter of 2-dnameth", function(test) {
  const holder = getHolder();
  runpp({
    holder,
    state: state2dnameth,
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const chart = scatter.Inner.model.charts[0];
    test.true(scatter.Inner.settings.showAxes, "Dynamic scatter should have axes");
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("Show tooltip for sample", function(test) {
  test.timeoutAfter(8e3);
  test.plan(2);
  const holder = getHolder();
  runpp({
    holder,
    //Fix for test failing because survival & summary sandboxs are not destroyed.
    state,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const chart = scatter.Inner.model.charts[0];
    const sample = groups[0].items[0];
    scatter.Inner.vm.scatterTooltip.showSampleTooltip(sample, 100, 100, chart);
    const tooltipDiv = scatter.Inner.view.dom.tooltip.d.node();
    const tree = scatter.Inner.vm.scatterTooltip.tree;
    const parentNode = tree.find((n) => n.id == "Acute lymphoblastic leukemia" && n.samples.length == 3);
    test.true(parentNode != null, "Tooltip should have 3 samples for Acute lymphoblastic leukemia");
    test.true(tooltipDiv != null, "Tooltip should be shown");
    scatter.Inner.view.dom.tooltip.hide();
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("Test scale dot", function(test) {
  test.timeoutAfter(8e3);
  test.plan(2);
  const holder = getHolder();
  const state2 = {
    plots: [
      {
        chartType: "sampleScatter",
        scaleDotTW: { id: "agedx", q: { mode: "continuous" } },
        name: "TermdbTest TSNE"
      }
    ]
  };
  runpp({
    holder,
    //Fix for test failing because survival & summary sandboxs are not destroyed.
    state: state2,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const self = scatter.Inner;
    const chart = scatter.Inner.model.charts[0];
    const dots = self.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    const minSize = self.settings.minShapeSize * self.zoom / 3;
    const maxSize = self.settings.maxShapeSize * self.zoom / 3;
    test.true(
      dots.find((dot) => dot.getAttribute("transform").includes(`scale(${minSize})`)) != null,
      `Dots with the minimum size should be found`
    );
    test.true(
      dots.find((dot) => dot.getAttribute("transform").includes(`scale(${maxSize})`)) != null,
      `Dots with the maximum size should be found`
    );
    if (test._ok) holder.remove();
    test.end();
  }
});
(0, import_tape.default)("Test lasso menus options", function(test) {
  test.timeoutAfter(8e3);
  runpp({
    state,
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    await triggerLassoMenu(scatter);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function triggerLassoMenu(scatter) {
    const group = groups[0];
    scatter.Inner.vm.scatterLasso.showLassoMenu(new PointerEvent("click"), group.items);
    const groupsMenu = scatter.Inner.view.dom.tip.d.selectAll("div.sja_menuoption").nodes();
    const options = ["List 2 samples", "Add to a group", "Add to a group and filter", "Open sample view"];
    for (const [i, node] of Object.entries(groupsMenu)) {
      const option = node.innerText;
      test.equal(option, options[i], `Should display ${option} in the menu`);
    }
    scatter.Inner.vm.scatterLasso.showTable(group, 0, 0, false);
    testSampleTable(scatter, group);
    groupsMenu[1].click();
    await sleep(1e3);
    test.equal(scatter.Inner.state.groups.length, 1, `Should create a group in mass state`);
    groupsMenu[2].click();
    await sleep(1e3);
    test.equal(scatter.Inner.state.groups.length, 2, `Should create another group in mass state`);
    test.true(
      scatter.Inner.state.termfilter?.filter?.lst[1]?.lst[0]?.tvs?.term.type == "samplelst",
      `Should create a samplelst filter in mass state`
    );
  }
  function testSampleTable(scatter, group) {
    const samplesRendered = scatter.Inner.view.dom.tip.d.selectAll(".sjpp_row_wrapper > td:nth-child(3)").nodes();
    const samples2Check = [];
    for (const item of samplesRendered) {
      samples2Check.push(item.innerHTML);
    }
    let foundSamples = 0;
    for (const sampleData of group.items) {
      if (samples2Check.some((d) => d == sampleData.sample)) ++foundSamples;
      else test.fail(`Sample = ${sampleData.sample} is not displayed in sample table`);
    }
    test.equal(samples2Check.length, foundSamples, `Should render all samples for ${group.name}`);
    scatter.Inner.view.dom.tip.hide();
  }
});
(0, import_tape.default)("Invalid colorTW.id", async function(test) {
  test.timeoutAfter(3e3);
  const message = `Should display error for colorTW.id not found within dataset`;
  const holder = getHolder();
  const id = "Not real data";
  try {
    runpp({
      holder,
      state: {
        plots: [
          {
            chartType: "sampleScatter",
            colorTW: { id },
            name: "TermdbTest TSNE"
          }
        ]
      }
    });
    const errorbar = await detectGte({ elem: holder.node(), selector: ".sja_errorbar" });
    test.equal(errorbar.length, 1, "Should display only one error message.");
    test.ok(
      errorbar[0].innerText.includes(`missing dictionary term for id=${id}`),
      `Should display, "Error: no term found for ${id} [sampleScatter getPlotConfig()]".`
    );
  } catch (e) {
    test.fail(message + ": " + e);
  }
  if (test._ok) holder.remove();
  test.end();
});
(0, import_tape.default)("Invalid colorTW.term", async function(test) {
  test.timeoutAfter(3e3);
  const holder = getHolder();
  const id = "Not real data";
  try {
    runpp({
      holder,
      state: {
        plots: [
          {
            chartType: "sampleScatter",
            colorTW: { term: { id } },
            name: "TermdbTest TSNE"
          }
        ]
      }
    });
    const errorbar = await detectGte({ elem: holder.node(), selector: ".sja_errorbar > div:nth-child(2)" });
    const error = "Error: Error: Type is not defined [sampleScatter getPlotConfig()]";
    test.true(errorbar[0].innerText.startsWith(error), `Should display, "${error}...".`);
  } catch (e) {
    test.fail(e);
  }
  if (test._ok) holder.remove();
  test.end();
});
(0, import_tape.default)("Invalid plot name", async function(test) {
  test.timeoutAfter(3e3);
  const message = `Should display error for invalid plot name`;
  const holder = getHolder();
  try {
    runpp({
      holder,
      state: {
        plots: [
          {
            chartType: "sampleScatter",
            colorTW: {
              id: "diaggrp"
            },
            name: "Not real data"
          }
        ]
      }
    });
    const errorbar = await Locator.init(holder.node()).shows(".sja_errorbar").get();
    test.equal(errorbar.length, 1, "Should display only one error message.");
    test.ok(
      errorbar[0].innerText.includes(`plot not found with plotName`),
      'Should display, "Error: plot not found with plotName: Not real data".'
    );
  } catch (e) {
    test.fail(message + ": " + e);
  }
  if (test._ok) holder.remove();
  test.end();
});
(0, import_tape.default)("Test legend", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: structuredClone(state),
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const samples = scatter.Inner.model.charts[0].data.samples;
    const scatterDiv = scatter.Inner.model.charts[0].chartDiv;
    await testHideCategory(scatter, samples);
    await testChangeColor(scatter, samples);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function testHideCategory(scatter, samples) {
    const key = "Acute lymphoblastic leukemia";
    const expectedNum = samples.filter((s) => s.category === key).length;
    const matched = await detectChildStyle({
      elem: scatter.Inner.view.dom.mainDiv.node(),
      selector: ".sjpcb-scatter-series > path",
      style: {
        fillOpacity: "0"
      },
      count: expectedNum,
      trigger: () => {
        const chart = scatter.Inner.model.charts[0];
        scatter.Inner.vm.legendvm.legendInteractivity.hideCategory(scatter.Inner.config.colorTW, key, true);
        scatter.Inner.app.dispatch({
          type: "plot_edit",
          id: scatter.Inner.id,
          config: { colorTW: scatter.Inner.config.colorTW }
        });
      }
      /* example of a custom matcher, instead of opts.style
               matcher(mutations, observer) {
                   const hidden = mutations.filter(m => m.target.__data__.category == key && m.target.style.fillOpacity == '0')
                   if (hidden.length >= expectedNum) return hidden.map(d => d.target)
               }*/
    });
    test.equal(
      matched.filter((t) => t.__data__.category == key).length,
      expectedNum,
      `Should remove all samples with category = ${key}`
    );
  }
  async function testChangeColor(scatter, samples) {
    const key = "Wilms tumor";
    const color = "blue";
    const expectedColor = rgb(color).toString();
    const expectedNum = samples.filter((s) => s.category === key).length;
    const targets = await detectChildAttr({
      elem: scatter.Inner.view.dom.mainDiv.node(),
      selector: ".sjpcb-scatter-series > path",
      observe: {
        attributeFilter: ["fill"]
      },
      /* example of opts.attr, instead of opts.matcher()
               attr: {
                   // key is name of attribute, value can be a string, number, or function
                   fill: value => {
                       return d3color.rgb(value).toString() === expectedColor
                   }
               },*/
      count: expectedNum,
      trigger: async () => {
        scatter.Inner.vm.legendvm.legendInteractivity.changeColor(key, color);
      },
      // example of a custom matcher, instead of opts.attr{}
      matcher(mutations) {
        const targets2 = mutations.filter((m) => rgb(m.target.getAttribute("fill")) == expectedColor);
        if (targets2.length >= expectedNum) return targets2.map((d) => d.target);
      }
    });
    test.equal(targets.length, 2, `Should change the color of the category = ${key} to blue`);
  }
});
(0, import_tape.default)("Render color groups", function(test) {
  test.timeoutAfter(3e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          colorTW: {
            id: "genetic_race",
            q: {
              customset: {
                groups: [
                  {
                    name: "non-Asian Ancestry",
                    type: "values",
                    values: [
                      { key: "European Ancestry", label: "European Ancestry" },
                      { key: "African Ancestry", label: "African Ancestry" },
                      { key: "Multi-Ancestry-Admixed", label: "Multi-Ancestry-Admixed" }
                    ]
                  },
                  {
                    name: "Asian Ancestry",
                    type: "values",
                    values: [{ key: "Asian Ancestry", label: "Asian Ancestry" }]
                  }
                ]
              }
            }
          },
          name: "TermdbTest TSNE"
        }
      ]
    },
    sampleScatter: {
      callbacks: { "postRender.test": runTests }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    await testColorLegend(scatter);
    await changeColorGroups(scatter);
    await testColorLegend(scatter);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function testColorLegend(scatter) {
    const legendLabels = await detectGte({
      elem: scatter.Inner.model.charts[0].chartDiv.node(),
      selector: 'text[name="sjpp-scatter-legend-label"]'
    });
    const groups2 = [];
    for (const group of legendLabels) {
      const label = group.innerHTML.split(",");
      groups2.push({
        label: label[0],
        samples: label[1].match(/[\d\.]+/g)
      });
    }
    test.equal(
      scatter.Inner.model.charts[0].colorLegend.size,
      groups2.length + 1,
      `Legend categories (# = ${groups2.length + 1}) should equal size of colorLegend (# = ${scatter.Inner.model.charts[0].colorLegend.size}) `
    );
    compareData2DOMLegend(scatter, groups2);
  }
  function compareData2DOMLegend(scatter, groups2) {
    for (const group of groups2) {
      const mapLeg = scatter.Inner.model.charts[0].colorLegend.get(group.label);
      test.ok(mapLeg, `Should display group custom label = ${group.label} in legend`);
      test.equal(
        `${mapLeg.sampleCount}`,
        group.samples[0],
        `Should show matching n = ${group.samples[0]} for ${group.label}`
      );
    }
  }
  async function changeColorGroups(scatter) {
    scatter.Inner.config.colorTW.q.customset = {
      groups: [
        {
          name: "European Ancestryy",
          type: "values",
          values: [{ key: "European Ancestry", label: "European Ancestry" }]
        },
        {
          name: "non-European Ancestry",
          type: "values",
          values: [
            { key: "Asian Ancestry", label: "Asian Ancestry" },
            { key: "African Ancestry", label: "African Ancestry" },
            { key: "Multi-Ancestry-Admixed", label: "Multi-Ancestry-Admixed" }
          ]
        }
      ]
    };
    await scatter.Inner.app.dispatch({
      type: "plot_edit",
      id: scatter.Inner.id,
      config: scatter.Inner.config
    });
  }
});
(0, import_tape.default)("Change symbol and reference size from menu", function(test) {
  test.timeoutAfter(1e4);
  runpp({
    state: structuredClone(open_state),
    sampleScatter: {
      callbacks: { "postRender.test": runTests }
    }
  });
  const testSymSize = 300;
  const testRefSize = 1;
  async function runTests(scatter) {
    rideInit({ arg: scatter, bus: scatter, eventType: "postRender.test" }).use(changeSymbolInput).to(testSymbolSize, { wait: 100 }).use(changeRefInput, { wait: 100 }).to(testRefDotSize, { wait: 300 }).done(test);
  }
  function changeSymbolInput(scatter) {
    const sizeInput = scatter.Inner.view.dom.controlsHolder.selectAll("input").nodes().find((e) => e.value == scatter.Inner.settings.size);
    sizeInput.value = testSymSize;
    sizeInput.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter" }));
  }
  function testSymbolSize(scatter) {
    test.equal(scatter.Inner.settings.size, testSymSize, `Should change symbol dot size to test value = ${testSymSize}`);
  }
  function changeRefInput(scatter) {
    const refInput = scatter.Inner.view.dom.controlsHolder.selectAll("input").nodes().find((e) => e.value == scatter.Inner.settings.refSize);
    refInput.value = testRefSize;
    refInput.dispatchEvent(new KeyboardEvent("keyup", { key: "Enter" }));
  }
  function testRefDotSize(scatter) {
    test.equal(
      scatter.Inner.settings.refSize,
      testRefSize,
      `Should change reference dot size to test value = ${testRefSize}`
    );
  }
});
(0, import_tape.default)("Change chart width and height from menu", function(test) {
  test.timeoutAfter(1e3);
  runpp({
    state: structuredClone(open_state),
    sampleScatter: {
      callbacks: { "postRender.test": runTests }
    }
  });
  const testWidth = 550;
  const testHeight = 550;
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    await testChartSizeChange(scatter);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function testChartSizeChange(scatter) {
    const widthInput = scatter.Inner.view.dom.controlsHolder.selectAll("input").nodes().find((e) => e.value == scatter.Inner.settings.svgw);
    widthInput.value = testWidth;
    const heightInput = scatter.Inner.view.dom.controlsHolder.selectAll("input").nodes().find((e) => e.value == scatter.Inner.settings.svgh);
    heightInput.value = testHeight;
    await detectAttr({
      target: scatter.Inner.view.dom.mainDiv.select("svg").node(),
      observe: {
        attributeFilter: ["height", "width"]
      },
      // count: 1,
      trigger() {
        widthInput.dispatchEvent(new Event("change"));
        heightInput.dispatchEvent(new Event("change"));
      }
      // matcher(mutations){
      // 	let foundH, foundW = 0
      // 	for (const mut of mutations) {
      // 		if (mut.type == 'width') ++foundW
      // 		if (mut.type == 'height') ++foundH
      // 	}
      // }
    });
    test.equal(
      scatter.Inner.settings.svgw,
      testWidth,
      `Chart width = ${scatter.Inner.settings.svgw} should be equal to test width = ${testWidth}`
    );
    test.equal(
      scatter.Inner.settings.svgh,
      testHeight,
      `Chart height = ${scatter.Inner.settings.svgh} should be equal to test height = ${testHeight}`
    );
  }
});
(0, import_tape.default)("Check/uncheck Show axes from menu", function(test) {
  test.timeoutAfter(4e3);
  runpp({
    state: structuredClone(open_state),
    sampleScatter: {
      callbacks: { "postRender.test": runTests }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    await showAxes(scatter, true);
    await showAxes(scatter, false);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function showAxes(scatter, isvisible) {
    const opacity = isvisible ? 1 : 0;
    const axesDiv = await detectStyle({
      target: scatter.Inner.view.dom.mainDiv.node().querySelector(".sjpcb-scatter-axis"),
      style: {
        opacity: `${opacity}`
      },
      trigger() {
        const axesCheckbox = scatter.Inner.view.dom.controlsHolder.select('input[data-testid="showAxes"]');
        axesCheckbox.property("checked", isvisible);
        axesCheckbox.node().dispatchEvent(new Event("change"));
      }
    });
    const axesStyle = getComputedStyle(axesDiv[0]);
    test.equal(axesStyle.opacity, `${opacity}`, `Should ${isvisible ? "show" : "hide"} axes`);
  }
});
(0, import_tape.default)("Click zoom in, zoom out, and reset buttons", function(test) {
  test.timeoutAfter(1e4);
  runpp({
    state: structuredClone(state),
    sampleScatter: {
      callbacks: {
        "postRender.test": runTests
      }
    }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    await testZoomIn(scatter);
    await testReset(scatter);
    await testZoomOut(scatter);
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
  async function testZoomIn(scatter) {
    const zoomin_bt = scatter.Inner.view.dom.toolsDiv.node().querySelector('div[name="sjpp-zoom-in-btn"]');
    const m = await detectTransform(scatter, zoomin_bt, 1.2);
    test.ok(m != null, `Plot should zoom in`);
  }
  async function testReset(scatter) {
    const reset_bt = scatter.Inner.view.dom.toolsDiv.node().querySelector('div[name="sjpp-reset-btn"]');
    const m = await detectTransform(scatter, reset_bt, 1);
    test.ok(m != null, `Plot should reset`);
  }
  async function testZoomOut(scatter) {
    const zoomout_bt = scatter.Inner.view.dom.toolsDiv.node().querySelector('div[name="sjpp-zoom-out-btn"]');
    const m = await detectTransform(scatter, zoomout_bt, 0.8);
    test.ok(m != null, `Plot should zoom out`);
  }
  async function detectTransform(scatter, btn, scale) {
    const target = await detectAttr({
      target: scatter.Inner.view.dom.mainDiv.node().querySelector(".sjpcb-scatter-series"),
      observe: {
        subtree: true,
        characterData: true,
        attributeFilter: ["transform"]
      },
      count: 1,
      trigger() {
        btn.click();
      },
      matcher(mutations) {
        for (const m of mutations) {
          if (m.attributeName == "transform" && m.target.attributes[1].value.includes(`scale(${scale})`)) return m;
        }
      }
    });
    return target;
  }
});
(0, import_tape.default)("colorTW=geneVariant with no groupsetting", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          name: "TermdbTest TSNE",
          colorTW: { term: { gene: "TP53", name: "TP53", type: "geneVariant" } }
        }
      ]
    },
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    test.true(
      dots.find((dot) => dot.getAttribute("fill") == mclass["M"].color),
      "At least a sample with MISSENSE color was expected"
    );
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("colorTW=geneVariant with groupsetting", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          name: "TermdbTest TSNE",
          colorTW: getGeneVariantTw()
        }
      ]
    },
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    const lab = "TP53 SNV/indel Mutated (somatic)";
    test.true(
      dots.find((d) => d.__data__.category == lab),
      `A dot with category=${lab}`
    );
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("colorTW=geneVariant with gene list", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          name: "TermdbTest TSNE",
          colorTW: getGenesetMutTw()
        }
      ]
    },
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    const lab = "TP53, KRAS, AKT1, BCR SNV/indel Mutated (somatic)";
    test.true(
      dots.find((d) => d.__data__.category == lab),
      `A dot with category=${lab}`
    );
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("colorTW=ssgsea", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          name: "TermdbTest TSNE",
          colorTW: getSsgseaTw()
        }
      ]
    },
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    test.true(
      dots.find((d) => Number.isFinite(d.__data__.category)),
      `A dot with category=number`
    );
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("singlecell map", function(test) {
  test.timeoutAfter(6e3);
  runpp({
    state: {
      plots: [
        {
          chartType: "sampleScatter",
          colorTW: getScctTw(),
          singleCellPlot: { name: "UMAP", sample: { sID: "1_patient" } }
        }
      ]
    },
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    test.true(dots.length, "some dots are loaded from singlecell map");
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("singlecell geneexp", function(test) {
  runpp({
    state: state2scgeneexp,
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    const dots = scatter.Inner.view.dom.mainDiv.selectAll(".sjpcb-scatter-series > path").nodes();
    test.true(dots.length, "some dots are loaded from singlecell map");
    if (test._ok) scatter.Inner.app.destroy();
    test.end();
  }
});
(0, import_tape.default)("Disco plot and lollipop", (test) => {
  test.timeoutAfter(2e3);
  const holder = getHolder();
  runpp({
    holder,
    state: state2ssgsea,
    sampleScatter: { callbacks: { "postRender.test": runTests } }
  });
  async function runTests(scatter) {
    scatter.on("postRender.test", null);
    const sampleWithMutDataFile = scatter.Inner.dom.mainDiv.select(".sjpcb-scatter-series").selectAll("path").filter((d) => d.sample === "3416").node();
    const box = sampleWithMutDataFile.getBoundingClientRect();
    sampleWithMutDataFile.dispatchEvent(
      new MouseEvent("click", {
        bubbles: true,
        clientX: box.x + box.width / 2,
        clientY: box.y + box.height / 2
      })
    );
    const chordTexts = await detectGte({
      elem: holder.node(),
      selector: ".chord-text",
      count: 1,
      trigger: () => {
        scatter.Inner.dom.tooltip.d.selectAll("button").filter(function() {
          return this.innerHTML == "Disco";
        }).node().click();
      }
    });
    const label = [...chordTexts].find((c) => c.__data__?.text === "TP53");
    if (!label) {
      test.failt("must have a TP53 gene label");
    } else {
      const trackLabelsG = await detectGte({
        elem: holder.node(),
        selector: '[data-testid="sja_sample_menu_opener"]',
        count: 2,
        trigger: () => {
          label.dispatchEvent(new MouseEvent("click"));
        }
      });
      await sleep(500);
      const trackLabels = [...trackLabelsG[0].querySelectorAll("text")];
      test.equal(
        trackLabels.filter((t) => t.innerHTML.includes("unknown data source")).length,
        0,
        "must not have an error after clicking a Disco plot gene label to launch a genome browser track"
      );
      if (test._ok) holder.remove();
      test.end();
    }
  }
});
//# sourceMappingURL=scatter.integration.spec-3EYTPY5B.js.map
