599 lines
22 KiB
JavaScript
599 lines
22 KiB
JavaScript
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
|
|
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
|
|
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
|
|
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
|
|
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
|
|
// ┃ 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 { API_VERSION, expect } from "@perspective-dev/test";
|
|
import path from "path";
|
|
import {
|
|
default_body,
|
|
add_and_execute_cell,
|
|
assert_no_error_in_cell,
|
|
execute_all_cells,
|
|
test_jupyter,
|
|
describe_jupyter,
|
|
} from "./utils.mjs";
|
|
|
|
import { fileURLToPath } from "url";
|
|
import { dirname } from "path";
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
|
const getEditMode = async (viewer) => {
|
|
return await viewer.evaluate(async (viewer) => {
|
|
return (await viewer.save()).plugin_config.edit_mode;
|
|
});
|
|
};
|
|
|
|
// utils.with_jupyterlab(process.env.__JUPYTERLAB_PORT__, () => {
|
|
describe_jupyter(
|
|
() => {
|
|
test_jupyter(
|
|
"Open arrow and csv from file browser",
|
|
[],
|
|
async ({ page }) => {
|
|
await page.locator("#tab-key-1-7").click();
|
|
await page
|
|
.locator(`.jp-DirListing-item[data-file-type="arrow"]`)
|
|
.click({ button: "right" });
|
|
|
|
await page.hover(`.lm-Menu .lm-Menu-item[data-type="submenu"]`);
|
|
await page
|
|
.locator(`.lm-Menu-item[data-command="filebrowser:open"]`)
|
|
.click();
|
|
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(14);
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(5);
|
|
},
|
|
);
|
|
|
|
// Basics
|
|
test_jupyter(
|
|
"Loads data",
|
|
[
|
|
"w = perspective.widget.PerspectiveWidget(arrow_data, columns=['f64', 'str', 'datetime'])",
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(3);
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(5);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Loads updates",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table, columns=['f64', 'str', 'datetime'])",
|
|
].join("\n"),
|
|
"w",
|
|
"table.update(arrow_data)",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(3);
|
|
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(10);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Loads a table",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table, columns=['f64', 'str', 'datetime'])",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(3);
|
|
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(5);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Loads AsyncTable",
|
|
[
|
|
`
|
|
import asyncio
|
|
server = perspective.Server()
|
|
sync_client = server.new_local_client()
|
|
sync_client.table({"Income": [5,4,3,2,1], "Expense": [4,3,2,1,1], "Profit": [1,1,1,1,0]}, name="Microstore")
|
|
proxy_sess = perspective.ProxySession(sync_client, lambda msg: asyncio.create_task(async_client.handle_response(msg)))
|
|
|
|
async_client = perspective.AsyncClient(proxy_sess.handle_request_async)
|
|
async_table = await async_client.open_table("Microstore")`,
|
|
"w = perspective.widget.PerspectiveWidget(async_table)",
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(3);
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(5);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Loads updates to AsyncTable",
|
|
[
|
|
[
|
|
`
|
|
import asyncio
|
|
server = perspective.Server()
|
|
sync_client = server.new_local_client()
|
|
sync_table = sync_client.table(arrow_data)
|
|
proxy_sess = perspective.ProxySession(sync_client, lambda msg: asyncio.create_task(async_client.handle_response(msg)))
|
|
|
|
async_client = perspective.AsyncClient(proxy_sess.handle_request_async)
|
|
async_table = await async_client.open_table(sync_table.get_name())`,
|
|
"w = perspective.widget.PerspectiveWidget(async_table, columns=['f64', 'str', 'datetime'])",
|
|
].join("\n"),
|
|
"w",
|
|
"sync_table.update(arrow_data)",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
expect(num_columns).toEqual(3);
|
|
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(10);
|
|
},
|
|
);
|
|
// Restore
|
|
|
|
test_jupyter(
|
|
"Loads with settings=False",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table, columns=['f64', 'str', 'datetime'], settings=False)",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
const settings = await viewer.evaluate(async (viewer) => {
|
|
return (await viewer.save()).settings;
|
|
});
|
|
|
|
expect(settings).toEqual(false);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Loads with edit_mode=EDIT",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table, plugin_config={'edit_mode': 'EDIT'})",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
const edit_mode = await getEditMode(viewer);
|
|
expect(edit_mode).toEqual("EDIT");
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Editable Toggle - from Python",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table)",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
let edit_mode = await getEditMode(viewer);
|
|
expect(edit_mode).toEqual("READ_ONLY");
|
|
|
|
await add_and_execute_cell(
|
|
page,
|
|
'w.plugin_config = {"edit_mode": "EDIT"}',
|
|
);
|
|
|
|
edit_mode = await getEditMode(viewer);
|
|
expect(edit_mode).toEqual("EDIT");
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Editable Toggle - from JS",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table)",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
let edit_mode = await getEditMode(viewer);
|
|
expect(edit_mode).toEqual("READ_ONLY");
|
|
|
|
await viewer.evaluate(async (viewer) => {
|
|
const edit =
|
|
viewer.children[1].shadowRoot.querySelector(
|
|
"span#edit_mode",
|
|
);
|
|
edit.click();
|
|
});
|
|
|
|
edit_mode = await getEditMode(viewer);
|
|
expect(edit_mode).toEqual("EDIT");
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Everything Else - Toggle from Python",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table)",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
let config = await viewer.evaluate(async (viewer) => {
|
|
return await viewer.save();
|
|
});
|
|
|
|
// Check default config
|
|
expect(config).toEqual({
|
|
version: API_VERSION,
|
|
columns_config: {},
|
|
aggregates: {},
|
|
columns: [
|
|
"ui8",
|
|
"i8",
|
|
"ui16",
|
|
"i16",
|
|
"ui32",
|
|
"i32",
|
|
"ui64",
|
|
"i64",
|
|
"f32",
|
|
"f64",
|
|
"bool",
|
|
"str",
|
|
"date",
|
|
"datetime",
|
|
],
|
|
expressions: {},
|
|
filter: [],
|
|
group_by: [],
|
|
plugin: "Datagrid",
|
|
plugin_config: {
|
|
columns: {},
|
|
edit_mode: "READ_ONLY",
|
|
scroll_lock: false,
|
|
},
|
|
settings: true,
|
|
sort: [],
|
|
split_by: [],
|
|
theme: "Pro Light",
|
|
title: null,
|
|
});
|
|
|
|
await add_and_execute_cell(
|
|
page,
|
|
`
|
|
w.plugin = "X Bar"
|
|
w.columns = ["ui8"]
|
|
w.filter = [["i8", "<", 50]]
|
|
w.group_by = ["date"]
|
|
w.split_by = ["bool"]
|
|
w.sort = [["date", "asc"]]
|
|
w.theme = "Pro Dark"`,
|
|
);
|
|
|
|
// grab the config again
|
|
config = await viewer.evaluate(async (viewer) => {
|
|
return await viewer.save();
|
|
});
|
|
|
|
// and check it
|
|
expect(config).toEqual({
|
|
version: API_VERSION,
|
|
columns_config: {},
|
|
aggregates: {},
|
|
columns: ["ui8"],
|
|
expressions: {},
|
|
filter: [["i8", "<", 50]],
|
|
group_by: ["date"],
|
|
plugin: "X Bar",
|
|
plugin_config: {},
|
|
settings: true,
|
|
sort: [["date", "asc"]],
|
|
split_by: ["bool"],
|
|
theme: "Pro Dark",
|
|
title: null,
|
|
});
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Everything Else - Toggle from JS",
|
|
[
|
|
[
|
|
"server = perspective.Server()",
|
|
"client = server.new_local_client()",
|
|
"table = client.table(arrow_data)",
|
|
"w = perspective.widget.PerspectiveWidget(table)",
|
|
].join("\n"),
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
const config = await viewer.evaluate(async (viewer) => {
|
|
return await viewer.save();
|
|
});
|
|
|
|
// Check default config
|
|
expect(config).toEqual({
|
|
version: API_VERSION,
|
|
columns_config: {},
|
|
aggregates: {},
|
|
columns: [
|
|
"ui8",
|
|
"i8",
|
|
"ui16",
|
|
"i16",
|
|
"ui32",
|
|
"i32",
|
|
"ui64",
|
|
"i64",
|
|
"f32",
|
|
"f64",
|
|
"bool",
|
|
"str",
|
|
"date",
|
|
"datetime",
|
|
],
|
|
expressions: {},
|
|
filter: [],
|
|
group_by: [],
|
|
plugin: "Datagrid",
|
|
plugin_config: {
|
|
columns: {},
|
|
scroll_lock: false,
|
|
edit_mode: "READ_ONLY",
|
|
},
|
|
settings: true,
|
|
sort: [],
|
|
split_by: [],
|
|
theme: "Pro Light",
|
|
title: null,
|
|
});
|
|
|
|
await viewer.evaluate(async (viewer, version) => {
|
|
viewer.restore({
|
|
version,
|
|
columns: ["ui8"],
|
|
filter: [["i8", "<", "50"]],
|
|
group_by: ["date"],
|
|
plugin: "X Bar",
|
|
settings: false,
|
|
sort: [["date", "asc"]],
|
|
split_by: ["bool"],
|
|
theme: "Pro Dark",
|
|
title: null,
|
|
});
|
|
|
|
return "";
|
|
}, API_VERSION);
|
|
|
|
const error_cells_dont_exist = await assert_no_error_in_cell(
|
|
page,
|
|
`
|
|
assert w.plugin == "X Bar"
|
|
assert w.columns == ["ui8"]
|
|
assert w.filter == [["i8", "<", "50"]]
|
|
assert w.group_by == ["date"]
|
|
assert w.split_by == ["bool"]
|
|
assert w.plugin_config == {}
|
|
assert w.settings == False
|
|
assert w.sort == [["date", "asc"]]
|
|
assert w.theme == "Pro Dark"
|
|
"Passed"`,
|
|
);
|
|
expect(error_cells_dont_exist).toBe(true);
|
|
},
|
|
);
|
|
|
|
test_jupyter(
|
|
"Edit from frontend - end to end",
|
|
[
|
|
'w = perspective.widget.PerspectiveWidget({"a": [True, False, True], "b": ["abc", "def", "ghi"]}, index="b", plugin_config={"edit_mode": "EDIT"})',
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
const viewer = await default_body(page);
|
|
|
|
// assert in python or else
|
|
let error_cells_dont_exist = await assert_no_error_in_cell(
|
|
page,
|
|
[
|
|
`assert w.table.view().to_columns() == {'a': [True, False, True], 'b': ['abc', 'def', 'ghi']}`,
|
|
`"Passed"`,
|
|
].join("\n"),
|
|
);
|
|
expect(error_cells_dont_exist).toBe(true);
|
|
|
|
// Toggle some values in the frontend
|
|
const bools = await page.$$(".psp-bool-type");
|
|
|
|
// do synchronous
|
|
for (let bool of bools) {
|
|
await bool.click();
|
|
}
|
|
|
|
// now check again
|
|
error_cells_dont_exist = await assert_no_error_in_cell(
|
|
page,
|
|
[
|
|
`assert w.table.view().to_columns() == {'a': [False, True, False], 'b': ['abc', 'def', 'ghi']}`,
|
|
`"Passed"`,
|
|
].join("\n"),
|
|
);
|
|
|
|
expect(error_cells_dont_exist).toBe(true);
|
|
},
|
|
);
|
|
|
|
test_jupyter("Restores from saved config", [], async ({ page }) => {
|
|
await execute_all_cells(page);
|
|
let errored = await assert_no_error_in_cell(
|
|
page,
|
|
`
|
|
server = perspective.Server()
|
|
client = server.new_local_client()
|
|
table = client.table(arrow_data)
|
|
w = perspective.widget.PerspectiveWidget(table)
|
|
config = w.save()
|
|
perpsective.PerspectiveWidget(df, **config)
|
|
`,
|
|
);
|
|
expect(errored).toBe(false);
|
|
});
|
|
|
|
test_jupyter(
|
|
"Toggles to datagrid and back regression",
|
|
[
|
|
"w = perspective.widget.PerspectiveWidget(arrow_data, columns=['f64', 'str', 'datetime'])",
|
|
"w",
|
|
],
|
|
async ({ page }) => {
|
|
await default_body(page);
|
|
const num_columns = await page
|
|
.locator("regular-table thead tr")
|
|
.first()
|
|
.evaluate((tr) => tr.childElementCount);
|
|
|
|
async function toggle(plugin) {
|
|
await page.locator(".plugin-select-item").click();
|
|
await page
|
|
.locator("#plugin_selector_container.open")
|
|
.waitFor();
|
|
|
|
await page
|
|
.locator(`[data-plugin=${plugin}].plugin-select-item`)
|
|
.click();
|
|
|
|
await page
|
|
.locator("#plugin_selector_container:not(.open)")
|
|
.waitFor();
|
|
|
|
await page.evaluate(async () => {
|
|
await document
|
|
.querySelector("perspective-viewer")
|
|
.flush();
|
|
});
|
|
}
|
|
|
|
await toggle('"X/Y Line"');
|
|
await toggle("Datagrid");
|
|
await toggle('"X/Y Line"');
|
|
await toggle("Datagrid");
|
|
|
|
// expect(num_columns).toEqual(3);
|
|
await expect(
|
|
page.locator("regular-table tbody tr"),
|
|
).toHaveCount(5);
|
|
},
|
|
);
|
|
|
|
// *************************
|
|
// UTILS
|
|
// *************************
|
|
test_jupyter(
|
|
"Run in Cell - Assert in Cell working",
|
|
[],
|
|
async ({ page }) => {
|
|
await execute_all_cells(page);
|
|
|
|
// assert_no_error_in_cell runs add_and_execute_cell internally so only need to check one
|
|
const error_cells_dont_exist = await assert_no_error_in_cell(
|
|
page,
|
|
"raise Exception('anything')",
|
|
);
|
|
expect(error_cells_dont_exist).toBe(false);
|
|
},
|
|
);
|
|
},
|
|
{ name: "Simple", root: path.join(__dirname, "..", "..") },
|
|
);
|
|
// });
|