Skip to content

Commit

Permalink
Merge pull request #863 from NeurodataWithoutBorders/even-more-coverage
Browse files Browse the repository at this point in the history
70% coverage
  • Loading branch information
CodyCBakerPhD authored Jun 17, 2024
2 parents 2138780 + 331d05e commit 8f24fbd
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 26 deletions.
6 changes: 4 additions & 2 deletions src/electron/frontend/core/components/BasicTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,9 @@ export class BasicTable extends LitElement {
for (let key in this.ignore) delete entries[key];
for (let key in this.ignore["*"] ?? {}) delete entries[key];

const schemaOrder = this.#itemSchema.order ?? [];
const order = this.keyColumn ? [this.keyColumn, ...schemaOrder] : schemaOrder;

// Sort Columns by Key Column and Requirement
const keys =
(this.#keys =
Expand All @@ -459,8 +462,7 @@ export class BasicTable extends LitElement {
...this.#itemSchema,
properties: entries,
},
this.keyColumn,
this.#itemSchema.order
order
));

// Try to guess the key column if unspecified
Expand Down
8 changes: 8 additions & 0 deletions src/electron/frontend/core/components/JSONSchemaForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,14 @@ export class JSONSchemaForm extends LitElement {

this.#resetLoadState();

// this.updateComplete.then(() => {
// this.#toggleRendered(); // Toggle internal render state

// // Promise.all([...Object.values(this.forms), ...Object.values(this.tables)]).map(o => o.updateComplete).then(() => {
// // this.#toggleRendered(); // Toggle internal render state
// // })
// })

const schema = this.schema ?? {};

this.resolved = structuredClone(this.results); // Track resolved values as a copy of the user-specified results
Expand Down
7 changes: 5 additions & 2 deletions src/electron/frontend/core/components/SimpleTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -968,14 +968,17 @@ export class SimpleTable extends LitElement {
for (let key in this.ignore) delete entries[key];
for (let key in this.ignore["*"] ?? {}) delete entries[key];

const schemaOrder = this.#itemSchema.order ?? [];
const order = this.keyColumn ? [this.keyColumn, ...schemaOrder] : schemaOrder;
if (!this.keyColumn && !order.includes("name")) order.unshift("name");

// Sort Columns by Key Column and Requirement
this.colHeaders = sortTable(
{
...this.#itemSchema,
properties: entries,
},
this.keyColumn,
this.#itemSchema.order ?? ["name"] // Specify the order of the columns
order // Specify the order of the columns
);

// Try to guess the key column if unspecified
Expand Down
31 changes: 11 additions & 20 deletions src/electron/frontend/core/components/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,15 @@ const rowSymbol = Symbol("row");

const maxRows = 20;

const isRequired = (col, schema) => {
return schema.required?.includes(col);
};
const isRequired = (col, schema) => schema.required?.includes(col);

export const getEditable = (value, rowData = {}, config, colName) => {
if (typeof config === "boolean") return config;
if (typeof config === "function") return config(value, rowData);
return getEditable(value, rowData, config?.[colName] ?? true);
};

export function sortTable(schema, keyColumn, order) {
export function sortTable(schema, order = []) {
const cols = Object.keys(schema.properties)

//Sort alphabetically
Expand All @@ -38,22 +36,15 @@ export function sortTable(schema, keyColumn, order) {
if (aRequired) return -1;
if (bRequired) return 1;
return 0;
})
.sort((a, b) => {
if (a === keyColumn) return -1;
if (b === keyColumn) return 1;
return 0;
});

return order
? cols.sort((a, b) => {
const idxA = order.indexOf(a);
const idxB = order.indexOf(b);
if (idxA === -1) return 1;
if (idxB === -1) return -1;
return idxA - idxB;
})
: cols;
return cols.sort((a, b) => {
const idxA = order.indexOf(a);
const idxB = order.indexOf(b);
if (idxA === -1) return 1;
if (idxB === -1) return -1;
return idxA - idxB;
});
}

// Inject scoped stylesheet
Expand Down Expand Up @@ -263,14 +254,14 @@ export class Table extends LitElement {
}

// Sort Columns by Key Column and Requirement
const order = this.keyColumn ? [this.keyColumn, ...(this.#itemSchema.order ?? [])] : this.#itemSchema.order;

const colHeaders = (this.colHeaders = sortTable(
{
...this.#itemSchema,
properties: entries,
},
this.keyColumn,
this.#itemSchema.order
order
));

// Try to guess the key column if unspecified
Expand Down
5 changes: 3 additions & 2 deletions tests/components/forms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ async function mountComponent(props) {

document.body.append(form)
await form.rendered
// await form.updateComplete;

return form;
}
Expand Down Expand Up @@ -163,10 +164,10 @@ describe('JSONSchemaForm', () => {

const row = users.getRow(0)
const newData = { name: 'John Doe', age: 30 }
await Promise.all(Object.entries(newData).map(([key, value]) => {
Object.entries(newData).map(([key, value]) => {
const cell = row.find(cell => cell.simpleTableInfo.col === key)
return cell.setInput(value)
}))
})

await sleep(100) // Wait for updates to register on the table

Expand Down
92 changes: 92 additions & 0 deletions tests/components/table.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// tests/table.test.js
import { expect, test, describe, vi, beforeEach, afterEach } from 'vitest';
import { Table, sortTable } from '../../src/electron/frontend/core/components/Table.js';
import { sleep } from '../puppeteer.js';

global.ResizeObserver = global.IntersectionObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}))

const createComponent = async (props = {}) => {
const element = new Table(props);
document.body.appendChild(element);
await element.updateComplete;
return element;
}

const itemSchema = {
properties: {
name: { type: 'string' },
age: { type: 'number' },
aliases: { type: 'array', items: { type: 'string' } }
},
required: ['name']
}

const schema = {
type: 'array',
items: itemSchema
}

describe('Table component', () => {


test('should render the table', async () => {
const element = await createComponent();
const div = element.querySelector('table');
expect(div).toBeTruthy();
element.remove()
});

test('should set schema and update columns', async () => {
const element = await createComponent({ schema });

const colHeaders = element.colHeaders;
expect(colHeaders).toEqual(['name', 'age', 'aliases']);
element.remove()
});

test('should add rows and validate data', async () => {
const element = await createComponent({ schema });

const row = { name: 'John Doe', age: 30, aliases: ['Johny', 'Doe'] }
element.data = [row];
await element.updated();
await sleep(1000);

const tableData = element.table.getData();
expect(tableData).toEqual([ Object.values(row) ]);
element.remove()
});

test('should work with key column', async () => {
const element = await createComponent({ schema, keyColumn: 'name' });

const key = 'John Doe';
const row = { age: 30, aliases: ['Johny', 'Doe'] }
const data = { [key]: row };
element.data = data;
await element.updated();
await sleep(1000);

const tableData = element.table.getData();
expect(tableData).toEqual([ [key, ...Object.values(row)] ]);
element.remove()
})

test('should sort table columns correctly', async () => {
const schema = {
properties: {
name: { type: 'string' },
age: { type: 'number' },
email: { type: 'string' },
},
required: ['name']
};

const sortedColumns = sortTable(schema, 'name', ['age', 'email']);
expect(sortedColumns).toEqual(['name', 'age', 'email']);
});
});
4 changes: 4 additions & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ export default defineConfig({
// Just rendering
"src/electron/frontend/core/components/CodeBlock.js",

// Depends on server communication
"src/electron/frontend/core/components/NWBFilePreview.js",

// Unclear how to test
"src/electron/frontend/utils/popups.ts",
"src/electron/frontend/utils/download.ts",
"src/electron/frontend/utils/upload.ts",
"src/electron/frontend/core/components/FileSystemSelector.js", // Uses Electron dialog
"src/electron/frontend/core/components/DandiResults.js", // Needs DANDI API Key and network access (unless possibly with a static mocked response)
],
},
},
Expand Down

0 comments on commit 8f24fbd

Please sign in to comment.