chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test, expect } from "@perspective-dev/test";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Context menu", () => {
|
||||
test("shows tables in the New Table submenu", async ({ page }) => {
|
||||
await page.evaluate(async () => {
|
||||
await window.__WORKER__.table("x\n1\n2\n", {
|
||||
name: "test_table_1",
|
||||
});
|
||||
|
||||
await window.__WORKER__.table("y\n3\n4\n", {
|
||||
name: "test_table_2",
|
||||
});
|
||||
});
|
||||
|
||||
// Right-click on the workspace to open context menu
|
||||
const workspace = page.locator("perspective-workspace");
|
||||
await workspace.click({
|
||||
button: "right",
|
||||
position: { x: 100, y: 100 },
|
||||
});
|
||||
|
||||
// Wait for the context menu to appear in the shadow DOM
|
||||
const shadowHost = page.locator("perspective-workspace");
|
||||
const menu = shadowHost.locator(".lm-Menu").first();
|
||||
await expect(menu).toBeVisible();
|
||||
|
||||
// Click on "New Table" to open the submenu
|
||||
const newTableItem = menu.locator(
|
||||
".lm-Menu-item:has(.lm-Menu-itemLabel:text('New Table'))",
|
||||
);
|
||||
await newTableItem.hover();
|
||||
|
||||
// Wait for submenu to appear
|
||||
const submenu = shadowHost.locator(".lm-Menu").nth(1);
|
||||
await expect(submenu).toBeVisible();
|
||||
|
||||
// Get the submenu content with table entries
|
||||
const submenuContent = submenu.locator(".lm-Menu-content");
|
||||
|
||||
// Wait for the table items to be populated (they are added asynchronously)
|
||||
// We expect at least our two test tables plus the default "superstore" table
|
||||
await expect(submenuContent.locator("> .lm-Menu-item")).toHaveCount(3, {
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
const menuItems = submenuContent.locator("> .lm-Menu-item");
|
||||
const itemCount = await menuItems.count();
|
||||
|
||||
// Get the labels of the first items (the tables)
|
||||
const labels = [];
|
||||
for (let i = 0; i < itemCount; i++) {
|
||||
const label = await menuItems
|
||||
.nth(i)
|
||||
.locator(".lm-Menu-itemLabel")
|
||||
.textContent();
|
||||
labels.push(label);
|
||||
}
|
||||
|
||||
// Verify our test tables appear in the menu
|
||||
expect(labels).toContain("test_table_1");
|
||||
expect(labels).toContain("test_table_2");
|
||||
expect(labels).toContain("superstore");
|
||||
});
|
||||
|
||||
test("context menu table entries have correct structure", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Create two tables and load the workspace
|
||||
await page.evaluate(async () => {
|
||||
await window.__WORKER__.table("a\n1\n", { name: "alpha" });
|
||||
await window.__WORKER__.table("b\n2\n", { name: "beta" });
|
||||
});
|
||||
|
||||
// Right-click on the workspace
|
||||
const workspace = page.locator("perspective-workspace");
|
||||
await workspace.click({
|
||||
button: "right",
|
||||
position: { x: 100, y: 100 },
|
||||
});
|
||||
|
||||
// Open the "New Table" submenu
|
||||
const shadowHost = page.locator("perspective-workspace");
|
||||
const menu = shadowHost.locator(".lm-Menu").first();
|
||||
await expect(menu).toBeVisible();
|
||||
|
||||
const newTableItem = menu.locator(
|
||||
".lm-Menu-item:has(.lm-Menu-itemLabel:text('New Table'))",
|
||||
);
|
||||
await newTableItem.hover();
|
||||
|
||||
const submenu = shadowHost.locator(".lm-Menu").nth(1);
|
||||
await expect(submenu).toBeVisible();
|
||||
|
||||
// Verify the DOM structure of table entries
|
||||
const submenuContent = submenu.locator(".lm-Menu-content");
|
||||
|
||||
// Wait for table items to be populated
|
||||
await expect(submenuContent.locator("> .lm-Menu-item")).toHaveCount(3, {
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
const firstItem = submenuContent.locator("> .lm-Menu-item").first();
|
||||
|
||||
// Check that the menu item has the expected Lumino classes
|
||||
await expect(firstItem).toHaveClass(/lm-Menu-item/);
|
||||
|
||||
// Check that it contains a label element
|
||||
const labelElement = firstItem.locator(".lm-Menu-itemLabel");
|
||||
await expect(labelElement).toBeVisible();
|
||||
|
||||
// Verify the label contains one of our table names
|
||||
const labelText = await labelElement.textContent();
|
||||
expect(["alpha", "beta", "superstore"]).toContain(labelText);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test } from "@perspective-dev/test";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Workspace table functions", () => {
|
||||
test("flush() waits until delete is resolved", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: { table: "superstore", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
const table = await window.__WORKER__.open_table("superstore");
|
||||
await workspace.restore(config);
|
||||
const viewer_removed =
|
||||
workspace.querySelector("perspective-viewer");
|
||||
|
||||
workspace.removeChild(viewer_removed);
|
||||
await viewer_removed.flush();
|
||||
await table.delete();
|
||||
}, config);
|
||||
});
|
||||
|
||||
test("flush() waits until restore is applied and delete is resolved", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: { table: "superstore", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
const table = await window.__WORKER__.open_table("superstore");
|
||||
workspace.restore(config); // no await
|
||||
await workspace.flush();
|
||||
const viewer_removed =
|
||||
workspace.querySelector("perspective-viewer");
|
||||
|
||||
workspace.removeChild(viewer_removed);
|
||||
await viewer_removed.flush();
|
||||
await table.delete();
|
||||
}, config);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test } from "@perspective-dev/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
async function setupTestWorkspace(page) {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const viewer = document.createElement("perspective-viewer");
|
||||
viewer.setAttribute("table", "superstore");
|
||||
viewer.setAttribute("name", "one");
|
||||
viewer.setAttribute("slot", "one");
|
||||
const viewer2 = document.createElement("perspective-viewer");
|
||||
viewer2.setAttribute("table", "superstore");
|
||||
viewer2.setAttribute("name", "two");
|
||||
viewer2.setAttribute("slot", "two");
|
||||
const workspace = document.getElementById("workspace");
|
||||
workspace.appendChild(viewer);
|
||||
workspace.appendChild(viewer2);
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const viewer = document.body.querySelector(
|
||||
'perspective-viewer[name="one"]',
|
||||
);
|
||||
const workspace = document.getElementById("workspace");
|
||||
workspace.removeChild(viewer);
|
||||
await workspace.flush();
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("Workspace DOM", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
test.describe("removeChild", () => {
|
||||
test("Remove One", async ({ page }) => {
|
||||
await setupTestWorkspace(page);
|
||||
|
||||
await compareLightDOMContents(
|
||||
page,
|
||||
"workspace-light-remove-one-child.txt",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
test.describe("removeChild", () => {
|
||||
test("Remove One", async ({ page }) => {
|
||||
await setupTestWorkspace(page);
|
||||
|
||||
await compareShadowDOMContents(
|
||||
page,
|
||||
"workspace-dark-remove-one-child.txt",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,472 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test, expect } from "@playwright/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
await page.evaluate(async () => {
|
||||
const { PerspectiveSelectDetail } = await import(
|
||||
"/node_modules/@perspective-dev/viewer/dist/cdn/perspective-viewer.js"
|
||||
);
|
||||
window.PerspectiveSelectDetail = PerspectiveSelectDetail;
|
||||
});
|
||||
});
|
||||
|
||||
function tests(context, compare) {
|
||||
// TODO: Implement this correctly
|
||||
test.skip("treemap filters work", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales"],
|
||||
plugin: "Treemap",
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const cfg = await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
const timer = Promise.withResolvers();
|
||||
workspace.addEventListener("workspace-layout-update", (x) => {
|
||||
timer.resolve();
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector("perspective-viewer-charts-treemap")
|
||||
.shadowRoot.querySelector("g.treemap > g")
|
||||
.dispatchEvent(new Event("click"));
|
||||
|
||||
await timer.promise;
|
||||
return await workspace.save();
|
||||
}, config);
|
||||
|
||||
expect(cfg.viewers.Two.filter).toEqual([["State", "==", "Alabama"]]);
|
||||
return compare(page, `${context}-treemap-filters-work.txt`);
|
||||
});
|
||||
|
||||
test("Datagrid filters work", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales"],
|
||||
plugin: "Datagrid",
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function awaitConfigChange() {
|
||||
return await page.evaluate(async () => {
|
||||
let resolve;
|
||||
const timer = new Promise((x) => {
|
||||
resolve = x;
|
||||
});
|
||||
|
||||
workspace.addEventListener("workspace-layout-update", resolve);
|
||||
await timer;
|
||||
workspace.removeEventListener(
|
||||
"workspace-layout-update",
|
||||
resolve,
|
||||
);
|
||||
|
||||
return await workspace.save();
|
||||
});
|
||||
}
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, config);
|
||||
|
||||
let cfgPromise = awaitConfigChange();
|
||||
await page
|
||||
.locator(".workspace-master-widget perspective-viewer-datagrid")
|
||||
.locator("tbody tr:nth-child(6) th:last-of-type")
|
||||
.click();
|
||||
|
||||
let cfg = await cfgPromise;
|
||||
expect(cfg.viewers.Two.filter).toEqual([["State", "==", "Colorado"]]);
|
||||
|
||||
cfgPromise = awaitConfigChange();
|
||||
await page
|
||||
.locator(".workspace-master-widget perspective-viewer-datagrid")
|
||||
.locator("tbody tr:nth-child(6) th:last-of-type")
|
||||
.click();
|
||||
|
||||
cfg = await cfgPromise;
|
||||
expect(cfg.viewers.Two.filter).toEqual([]);
|
||||
|
||||
return compare(page, `${context}-datagrid-filters-work.txt`);
|
||||
});
|
||||
|
||||
test("removeConfigs removes a programmatically applied filter from slave viewers", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales"],
|
||||
plugin: "Datagrid",
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function awaitConfigChange() {
|
||||
return await page.evaluate(async () => {
|
||||
let resolve;
|
||||
const timer = new Promise((x) => {
|
||||
resolve = x;
|
||||
});
|
||||
|
||||
workspace.addEventListener("workspace-layout-update", resolve);
|
||||
await timer;
|
||||
workspace.removeEventListener(
|
||||
"workspace-layout-update",
|
||||
resolve,
|
||||
);
|
||||
|
||||
return await workspace.save();
|
||||
});
|
||||
}
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, config);
|
||||
|
||||
// Apply a filter for "Category" via programmatic dispatch.
|
||||
// "Category" is not in the master's group_by/split_by/filter, so it
|
||||
// would not be cleared by the candidates mechanism on deselect.
|
||||
let cfgPromise = awaitConfigChange();
|
||||
await page.evaluate(async () => {
|
||||
const masterViewer = document.querySelector(
|
||||
".workspace-master-widget",
|
||||
);
|
||||
masterViewer.dispatchEvent(
|
||||
new CustomEvent("perspective-global-filter", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: new PerspectiveSelectDetail(
|
||||
true,
|
||||
{},
|
||||
["Category"],
|
||||
[],
|
||||
[{ filter: [["Category", "==", "Furniture"]] }],
|
||||
),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
let cfg = await cfgPromise;
|
||||
expect(cfg.viewers.Two.filter).toEqual([
|
||||
["Category", "==", "Furniture"],
|
||||
]);
|
||||
|
||||
// Use removeConfigs to explicitly clear the Category filter from
|
||||
// slave viewers.
|
||||
cfgPromise = awaitConfigChange();
|
||||
await page.evaluate(async () => {
|
||||
const masterViewer = document.querySelector(
|
||||
".workspace-master-widget",
|
||||
);
|
||||
masterViewer.dispatchEvent(
|
||||
new CustomEvent("perspective-global-filter", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: new PerspectiveSelectDetail(
|
||||
true,
|
||||
{},
|
||||
[],
|
||||
[{ filter: [["Category", "==", "Furniture"]] }],
|
||||
[],
|
||||
),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
cfg = await cfgPromise;
|
||||
expect(cfg.viewers.Two.filter).toEqual([]);
|
||||
});
|
||||
|
||||
test("removeConfigs preserves other slave filters while clearing targeted column", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales"],
|
||||
plugin: "Datagrid",
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function awaitConfigChange() {
|
||||
return await page.evaluate(async () => {
|
||||
let resolve;
|
||||
const timer = new Promise((x) => {
|
||||
resolve = x;
|
||||
});
|
||||
|
||||
workspace.addEventListener("workspace-layout-update", resolve);
|
||||
await timer;
|
||||
workspace.removeEventListener(
|
||||
"workspace-layout-update",
|
||||
resolve,
|
||||
);
|
||||
|
||||
return await workspace.save();
|
||||
});
|
||||
}
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, config);
|
||||
|
||||
// Apply filters for both "Category" and "Segment" via programmatic
|
||||
// dispatch.
|
||||
let cfgPromise = awaitConfigChange();
|
||||
await page.evaluate(async () => {
|
||||
const masterViewer = document.querySelector(
|
||||
".workspace-master-widget",
|
||||
);
|
||||
masterViewer.dispatchEvent(
|
||||
new CustomEvent("perspective-global-filter", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: new PerspectiveSelectDetail(
|
||||
true,
|
||||
{},
|
||||
["Category", "Segment"],
|
||||
[],
|
||||
[
|
||||
{
|
||||
filter: [
|
||||
["Category", "==", "Furniture"],
|
||||
["Segment", "==", "Consumer"],
|
||||
],
|
||||
},
|
||||
],
|
||||
),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
let cfg = await cfgPromise;
|
||||
expect(cfg.viewers.Two.filter).toEqual([
|
||||
["Category", "==", "Furniture"],
|
||||
["Segment", "==", "Consumer"],
|
||||
]);
|
||||
|
||||
// Remove only "Category"; "Segment" filter should be preserved.
|
||||
cfgPromise = awaitConfigChange();
|
||||
await page.evaluate(async () => {
|
||||
const masterViewer = document.querySelector(
|
||||
".workspace-master-widget",
|
||||
);
|
||||
masterViewer.dispatchEvent(
|
||||
new CustomEvent("perspective-global-filter", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: new PerspectiveSelectDetail(
|
||||
true,
|
||||
{},
|
||||
[],
|
||||
[{ filter: [["Category", "==", "Furniture"]] }],
|
||||
[],
|
||||
),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
cfg = await cfgPromise;
|
||||
// Category is cleared, Segment is preserved.
|
||||
expect(cfg.viewers.Two.filter).toEqual([["Segment", "==", "Consumer"]]);
|
||||
});
|
||||
|
||||
test("Child classes of datagrid behave the same way", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales"],
|
||||
plugin: "My Datagrid",
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async () => {
|
||||
class MyGrid extends customElements.get(
|
||||
"perspective-viewer-datagrid",
|
||||
) {
|
||||
get_static_config() {
|
||||
return {
|
||||
...super.get_static_config(),
|
||||
name: "My Datagrid",
|
||||
};
|
||||
}
|
||||
}
|
||||
customElements.define("my-grid", MyGrid);
|
||||
customElements.get("perspective-viewer").registerPlugin("my-grid");
|
||||
});
|
||||
|
||||
async function awaitConfigChange() {
|
||||
return await page.evaluate(async () => {
|
||||
let resolve;
|
||||
const timer = new Promise((x) => {
|
||||
resolve = x;
|
||||
});
|
||||
|
||||
workspace.addEventListener("workspace-layout-update", resolve);
|
||||
await timer;
|
||||
workspace.removeEventListener(
|
||||
"workspace-layout-update",
|
||||
resolve,
|
||||
);
|
||||
|
||||
return await workspace.save();
|
||||
});
|
||||
}
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, config);
|
||||
|
||||
let cfgPromise = awaitConfigChange();
|
||||
await page
|
||||
.locator(".workspace-master-widget my-grid")
|
||||
.locator("tbody tr:nth-child(6) th:last-of-type")
|
||||
|
||||
.click();
|
||||
let cfg = await cfgPromise;
|
||||
|
||||
expect(cfg.viewers.Two.filter).toEqual([["State", "==", "Colorado"]]);
|
||||
|
||||
cfgPromise = awaitConfigChange();
|
||||
await page
|
||||
.locator(".workspace-master-widget my-grid")
|
||||
.locator("tbody tr:nth-child(6) th:last-of-type")
|
||||
.click({
|
||||
delay: 10,
|
||||
});
|
||||
cfg = await cfgPromise;
|
||||
|
||||
// console.log("OLD", cfg.viewers.Two.filter);
|
||||
// await page.evaluate(async () => {
|
||||
// await new Promise((r) => setTimeout(r, 5000));
|
||||
// });
|
||||
// cfg = await page.evaluate(async () => {
|
||||
// const cfg = await workspace.save();
|
||||
// console.log("NEW", JSON.stringify(cfg.viewers.Two.filter));
|
||||
// return cfg;
|
||||
// });
|
||||
|
||||
expect(cfg.viewers.Two.filter).toEqual([]);
|
||||
|
||||
return compare(page, `${context}-my-datagrid-filters-work.txt`);
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("Workspace global filters", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
tests("light-dom", compareLightDOMContents);
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
tests("shadow-dom", compareShadowDOMContents);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test } from "@perspective-dev/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
async function createOneWorkspace(page) {
|
||||
// await new Promise((x) => setTimeout(x, 2000));
|
||||
await page.evaluate(async () => {
|
||||
document.querySelector("perspective-workspace").innerHTML = `
|
||||
<perspective-viewer table="superstore"></perspective-viewer>
|
||||
`;
|
||||
|
||||
const workspace = document.body.querySelector("perspective-workspace");
|
||||
await workspace.load(window.__WORKER__);
|
||||
await workspace.flush();
|
||||
});
|
||||
}
|
||||
|
||||
async function createMultipleViewers(page) {
|
||||
await page.evaluate(async () => {
|
||||
document.querySelector("perspective-workspace").innerHTML = `
|
||||
<perspective-viewer table="superstore"></perspective-viewer>
|
||||
<perspective-viewer table="superstore"></perspective-viewer>
|
||||
`;
|
||||
|
||||
const workspace = document.body.querySelector("perspective-workspace");
|
||||
await workspace.flush();
|
||||
});
|
||||
}
|
||||
|
||||
async function createMultipleViewersWithNames(page) {
|
||||
await page.evaluate(async () => {
|
||||
document.querySelector("perspective-workspace").innerHTML = `
|
||||
<perspective-viewer name="Table 1" table="superstore"></perspective-viewer>
|
||||
<perspective-viewer name="Table 2" table="superstore"></perspective-viewer>
|
||||
`;
|
||||
|
||||
const workspace = document.body.querySelector("perspective-workspace");
|
||||
await workspace.flush();
|
||||
});
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Workspace HTML", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
test("Create One", async ({ page }) => {
|
||||
await createOneWorkspace(page);
|
||||
await compareLightDOMContents(
|
||||
page,
|
||||
"workspace-html-light-create-one.txt",
|
||||
);
|
||||
});
|
||||
|
||||
test("Create Multiple", async ({ page }) => {
|
||||
await createMultipleViewers(page);
|
||||
await compareLightDOMContents(
|
||||
page,
|
||||
"workspace-html-light-create-multiple.txt",
|
||||
);
|
||||
});
|
||||
|
||||
test("Create Multiple with names", async ({ page }) => {
|
||||
await createMultipleViewersWithNames(page);
|
||||
await compareLightDOMContents(
|
||||
page,
|
||||
"workspace-html-light-create-multiple-with-names.txt",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
test("Create One", async ({ page }) => {
|
||||
await createOneWorkspace(page);
|
||||
await compareShadowDOMContents(
|
||||
page,
|
||||
"workspace-html-shadow-create-one.txt",
|
||||
);
|
||||
});
|
||||
|
||||
test("Create Multiple", async ({ page }) => {
|
||||
await createMultipleViewers(page);
|
||||
await compareShadowDOMContents(
|
||||
page,
|
||||
"workspace-html-shadow-create-multiple.txt",
|
||||
);
|
||||
});
|
||||
|
||||
test("Create Multiple with names", async ({ page }) => {
|
||||
await createMultipleViewersWithNames(page);
|
||||
await compareShadowDOMContents(
|
||||
page,
|
||||
"workspace-html-shadow-create-multiple-with-names.txt",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,260 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test, expect } from "@perspective-dev/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function tests(context, compare) {
|
||||
test("restore workspace with detail only", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: { table: "superstore", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
}, config);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-restore-workspace-with-detail-only.txt`,
|
||||
);
|
||||
});
|
||||
|
||||
test("restore workspace with master and detail", async ({ page }) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: {
|
||||
table: "superstore",
|
||||
name: "Test",
|
||||
group_by: ["State"],
|
||||
columns: ["Sales", "Profit"],
|
||||
},
|
||||
Two: { table: "superstore", name: "One" },
|
||||
},
|
||||
master: {
|
||||
widgets: ["One"],
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["Two"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
}, config);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-restore-workspace-with-master-and-detail.txt`,
|
||||
);
|
||||
});
|
||||
|
||||
test("restore workspace is symmetric with addViewer", async ({ page }) => {
|
||||
const initial = await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.addViewer({ table: "superstore" });
|
||||
await workspace.flush();
|
||||
const result = await workspace.save();
|
||||
return result;
|
||||
});
|
||||
|
||||
const second = await page.evaluate(async (initial) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(initial);
|
||||
await workspace.flush();
|
||||
return await workspace.save();
|
||||
}, initial);
|
||||
|
||||
expect(initial).toEqual(second);
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-restore-workspace-is-symmetric-with-addviewer.txt`,
|
||||
);
|
||||
});
|
||||
|
||||
test.describe("Toggle master/detail", () => {
|
||||
test("restore a blank view removes master panel", async ({ page }) => {
|
||||
const config = {
|
||||
detail: {
|
||||
main: {
|
||||
type: "tab-area",
|
||||
widgets: ["PERSPECTIVE_GENERATED_ID_1"],
|
||||
currentIndex: 0,
|
||||
},
|
||||
},
|
||||
master: { widgets: ["PERSPECTIVE_GENERATED_ID_0"], sizes: [1] },
|
||||
viewers: {
|
||||
PERSPECTIVE_GENERATED_ID_0: {
|
||||
table: "superstore",
|
||||
},
|
||||
PERSPECTIVE_GENERATED_ID_1: {
|
||||
table: "superstore",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const empty_config = {
|
||||
detail: {},
|
||||
viewers: {},
|
||||
};
|
||||
|
||||
// const x = await page.evaluate(async (config) => {
|
||||
// const workspace = document.getElementById("workspace");
|
||||
// await workspace.restore(config);
|
||||
// await workspace.flush();
|
||||
// return workspace.outerHTML;
|
||||
// }, config);
|
||||
|
||||
// test.expect(x).toEqual(
|
||||
// `<perspective-workspace id=\"workspace\"><perspective-viewer slot=\"PERSPECTIVE_GENERATED_ID_1\" table=\"superstore\" theme=\"Pro Light\" class=\"lm-DockPanel-widget\"><perspective-viewer-datagrid data-edit-mode=\"READ_ONLY\" style=\"position: absolute; inset: 0px; opacity: 1;\" class=\"edit-mode-allowed\"></perspective-viewer-datagrid><perspective-viewer-datagrid-toolbar slot=\"statusbar-extra\"></perspective-viewer-datagrid-toolbar></perspective-viewer><perspective-viewer slot=\"PERSPECTIVE_GENERATED_ID_0\" table=\"superstore\" theme=\"Pro Light\" class=\"workspace-master-widget lm-SplitPanel-child\" selectable=\"\"><perspective-viewer-datagrid data-edit-mode=\"READ_ONLY\" style=\"position: absolute; inset: 0px; opacity: 1;\"></perspective-viewer-datagrid><perspective-viewer-datagrid-toolbar slot=\"statusbar-extra\"></perspective-viewer-datagrid-toolbar></perspective-viewer></perspective-workspace>`,
|
||||
// );
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, empty_config);
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-restore-a-blank-view-removes-master-panel.txt`,
|
||||
);
|
||||
});
|
||||
|
||||
test("restore a view which reuses a master viewer, removes master panel", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
detail: {
|
||||
main: {
|
||||
type: "tab-area",
|
||||
widgets: ["PERSPECTIVE_GENERATED_ID_1"],
|
||||
currentIndex: 0,
|
||||
},
|
||||
},
|
||||
master: { widgets: ["PERSPECTIVE_GENERATED_ID_0"], sizes: [1] },
|
||||
viewers: {
|
||||
PERSPECTIVE_GENERATED_ID_0: {
|
||||
table: "superstore",
|
||||
title: "One",
|
||||
},
|
||||
PERSPECTIVE_GENERATED_ID_1: {
|
||||
table: "superstore",
|
||||
title: "Two",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const config2 = {
|
||||
detail: {
|
||||
main: {
|
||||
type: "split-area",
|
||||
orientation: "horizontal",
|
||||
children: [
|
||||
{
|
||||
type: "tab-area",
|
||||
widgets: ["PERSPECTIVE_GENERATED_ID_0"],
|
||||
currentIndex: 0,
|
||||
},
|
||||
{
|
||||
type: "tab-area",
|
||||
widgets: ["PERSPECTIVE_GENERATED_ID_1"],
|
||||
currentIndex: 0,
|
||||
},
|
||||
],
|
||||
sizes: [0.5, 0.5],
|
||||
},
|
||||
},
|
||||
master: { widgets: [], sizes: [] },
|
||||
viewers: {
|
||||
PERSPECTIVE_GENERATED_ID_0: {
|
||||
table: "superstore",
|
||||
title: "One",
|
||||
},
|
||||
PERSPECTIVE_GENERATED_ID_1: {
|
||||
table: "superstore",
|
||||
title: "Two",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// const x = await page.evaluate(async (config) => {
|
||||
// const workspace = document.getElementById("workspace");
|
||||
// await workspace.restore(config);
|
||||
// await workspace.flush();
|
||||
// return workspace.outerHTML;
|
||||
// }, config);
|
||||
|
||||
// test.expect(x).toEqual(
|
||||
// `<perspective-workspace id="workspace"><perspective-viewer slot="PERSPECTIVE_GENERATED_ID_1" table="superstore" theme="Pro Light" class="lm-DockPanel-widget"><perspective-viewer-datagrid data-edit-mode="READ_ONLY" style="position: absolute; inset: 0px; opacity: 1;" class="edit-mode-allowed"></perspective-viewer-datagrid><perspective-viewer-datagrid-toolbar slot="statusbar-extra"></perspective-viewer-datagrid-toolbar></perspective-viewer><perspective-viewer slot="PERSPECTIVE_GENERATED_ID_0" table="superstore" theme="Pro Light" class="workspace-master-widget lm-SplitPanel-child" selectable=""><perspective-viewer-datagrid data-edit-mode="READ_ONLY" style="position: absolute; inset: 0px; opacity: 1;"></perspective-viewer-datagrid><perspective-viewer-datagrid-toolbar slot="statusbar-extra"></perspective-viewer-datagrid-toolbar></perspective-viewer></perspective-workspace>`,
|
||||
// );
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.flush();
|
||||
}, config2);
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-restore-which-reseats-master-viewer.txt`,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("Workspace restore", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
tests("light-dom", compareLightDOMContents);
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
tests("shadow-dom", compareShadowDOMContents);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,164 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test, expect } from "@perspective-dev/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function tests(context, compare) {
|
||||
// TODO: 3.x `Client` has no exact `replaceTable`
|
||||
test.skip("replaceTable() frees the `Table` before resolution", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: { table: "superstore", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.restore(config);
|
||||
await workspace.replaceTable(
|
||||
"superstore",
|
||||
window.__WORKER__.table("x\n1"),
|
||||
);
|
||||
await window.__TABLE__.delete();
|
||||
}, config);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(page, `${context}-replace-table-frees-table.txt`);
|
||||
});
|
||||
|
||||
test.skip("replaceTable() works when previous table errored", async ({
|
||||
page,
|
||||
}) => {
|
||||
const config = {
|
||||
viewers: {
|
||||
One: { table: "errored", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await page.evaluate(async (config) => {
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.addTable(
|
||||
"errored",
|
||||
new Promise((_, reject) => setTimeout(reject, 50)),
|
||||
);
|
||||
|
||||
try {
|
||||
await workspace.restore(config);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return e.toString();
|
||||
}
|
||||
}, config);
|
||||
|
||||
// NOTE This is the error message we expect when `restore()` is called
|
||||
// without a `Table`, subject to change.
|
||||
expect(result).toEqual(
|
||||
"Error: Failed to construct table from JsValue(undefined)",
|
||||
);
|
||||
await page.evaluate(async () => {
|
||||
await workspace.replaceTable(
|
||||
"errored",
|
||||
window.__WORKER__.table("x\n1"),
|
||||
);
|
||||
});
|
||||
|
||||
await page.evaluate(async () => {
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`${context}-replace-table-works-with-errored-table.txt`,
|
||||
);
|
||||
});
|
||||
|
||||
test("removeTable() smoke test", async ({ page }) => {
|
||||
await page.evaluate(async () => {
|
||||
await window.__WORKER__.table("x\n1\n", { name: "temptable" });
|
||||
const workspace = document.getElementById("workspace");
|
||||
await workspace.load(window.__WORKER__);
|
||||
await workspace.restore({
|
||||
viewers: {
|
||||
One: { table: "temptable", name: "One" },
|
||||
},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: ["One"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
await page.evaluate(async () => {
|
||||
await workspace.restore({
|
||||
viewers: {},
|
||||
detail: {
|
||||
main: {
|
||||
currentIndex: 0,
|
||||
type: "tab-area",
|
||||
widgets: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(page, `${context}-table-delete-works.txt`);
|
||||
});
|
||||
}
|
||||
|
||||
test.describe("Workspace table functions", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
tests("light-dom", compareLightDOMContents);
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
tests("shadow-dom", compareShadowDOMContents);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
||||
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
||||
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
||||
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
||||
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
||||
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
|
||||
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
|
||||
// ┃ This file is part of the Perspective library, distributed under the terms ┃
|
||||
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
|
||||
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
import { test } from "@perspective-dev/test";
|
||||
import {
|
||||
compareLightDOMContents,
|
||||
compareShadowDOMContents,
|
||||
} from "@perspective-dev/test";
|
||||
|
||||
const BAD_LAYOUT = {
|
||||
sizes: [1],
|
||||
detail: {
|
||||
main: {
|
||||
type: "tab-area",
|
||||
widgets: [
|
||||
"PERSPECTIVE_GENERATED_ID_0",
|
||||
"PERSPECTIVE_GENERATED_ID_1",
|
||||
],
|
||||
currentIndex: 1,
|
||||
},
|
||||
},
|
||||
mode: "globalFilters",
|
||||
viewers: {
|
||||
PERSPECTIVE_GENERATED_ID_0: {
|
||||
plugin: "Sunburst",
|
||||
plugin_config: {},
|
||||
settings: false,
|
||||
theme: null,
|
||||
group_by: ["State"],
|
||||
split_by: [],
|
||||
columns: ["Quantity", null, null],
|
||||
filter: [],
|
||||
sort: [],
|
||||
expressions: {},
|
||||
aggregates: {},
|
||||
master: false,
|
||||
name: "one",
|
||||
table: "superstore",
|
||||
linked: false,
|
||||
},
|
||||
PERSPECTIVE_GENERATED_ID_1: {
|
||||
plugin: "Sunburst",
|
||||
plugin_config: {},
|
||||
settings: false,
|
||||
theme: null,
|
||||
group_by: ["State"],
|
||||
split_by: [],
|
||||
columns: ["Sales", null, null],
|
||||
filter: [],
|
||||
sort: [],
|
||||
expressions: {},
|
||||
aggregates: {},
|
||||
master: false,
|
||||
name: "two",
|
||||
table: "superstore",
|
||||
linked: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function tests(context, compare) {
|
||||
test.describe("visibility", () => {
|
||||
test("Sunburst charts do not loop forever when disconnected from DOM", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.evaluate(async (layout) => {
|
||||
await window.workspace.restore(layout);
|
||||
}, BAD_LAYOUT);
|
||||
|
||||
await page.evaluate(async () => {
|
||||
const viewer = document.body.querySelector(
|
||||
"perspective-viewer[slot=PERSPECTIVE_GENERATED_ID_0]",
|
||||
);
|
||||
const workspace = document.getElementById("workspace");
|
||||
workspace.removeChild(viewer);
|
||||
await workspace.flush();
|
||||
});
|
||||
|
||||
return compare(
|
||||
page,
|
||||
`sunburst-charts-does-not-loop-${context}.txt`,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/tools/test/src/html/workspace-test.html");
|
||||
await page.evaluate(async () => {
|
||||
while (!window["__TEST_PERSPECTIVE_READY__"]) {
|
||||
await new Promise((x) => setTimeout(x, 10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Workspace Visibility", () => {
|
||||
test.describe("Light DOM", () => {
|
||||
tests("light-dom", compareLightDOMContents);
|
||||
});
|
||||
|
||||
test.describe("Shadow DOM", () => {
|
||||
tests("shadow-dom", compareShadowDOMContents);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user