[Feature] Add language #19
7 changed files with 168 additions and 13 deletions
|
@ -1,5 +1,6 @@
|
||||||
[test]
|
[test]
|
||||||
coverage = true
|
coverage = true
|
||||||
|
coverageSkipTestFiles = true
|
||||||
coverageReporter = ['text', 'lcov']
|
coverageReporter = ['text', 'lcov']
|
||||||
coverageDir = './.coverage'
|
coverageDir = './.coverage'
|
||||||
preload = "./test.config.ts"
|
preload = "./test.config.ts"
|
||||||
|
|
133
src/components/table/dataset.spec.ts
Normal file
133
src/components/table/dataset.spec.ts
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import { describe, expect, it } from "bun:test";
|
||||||
|
import { createDataSet } from "./dataset";
|
||||||
|
|
||||||
|
interface DataEntry {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
const defaultData: DataEntry[] = [
|
||||||
|
{ id: '1', name: 'a first name', amount: 30 },
|
||||||
|
{ id: '2', name: 'a second name', amount: 20 },
|
||||||
|
{ id: '3', name: 'a third name', amount: 10 },
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('dataset', () => {
|
||||||
|
describe('createDataset', () => {
|
||||||
|
it('can create an instance', async () => {
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const actual = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(actual).toMatchObject({ data: defaultData })
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can sort by a property', async () => {
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const actual = createDataSet(defaultData, { sort: { by: 'amount', reversed: false } });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(actual.nodes()).toEqual([
|
||||||
|
expect.objectContaining({ key: 2 }),
|
||||||
|
expect.objectContaining({ key: 1 }),
|
||||||
|
expect.objectContaining({ key: 0 }),
|
||||||
|
])
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can group by a property', async () => {
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const actual = createDataSet(defaultData, { group: { by: 'name' } });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(actual).toEqual(expect.objectContaining({ data: defaultData }))
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mutate', () => {
|
||||||
|
it('mutates the value', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.mutate(0, 'amount', 100);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.value[0]!.amount).toBe(100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mutateEach', () => {
|
||||||
|
it('mutates all the entries', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.mutateEach(entry => ({ ...entry, amount: entry.amount + 5 }));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.value).toEqual([
|
||||||
|
expect.objectContaining({ amount: 35 }),
|
||||||
|
expect.objectContaining({ amount: 25 }),
|
||||||
|
expect.objectContaining({ amount: 15 }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('remove', () => {
|
||||||
|
it('removes the 2nd entry', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.remove([1]);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.value[1]).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insert', () => {
|
||||||
|
it('adds an entry to the dataset', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.insert({ id: '4', name: 'name', amount: 100 });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.value[3]).toEqual({ id: '4', name: 'name', amount: 100 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sort', () => {
|
||||||
|
it('can set the sorting', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.sort({ by: 'id', reversed: true });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.sorting).toEqual({ by: 'id', reversed: true });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('group', () => {
|
||||||
|
it('can set the grouping', async () => {
|
||||||
|
// Arrange
|
||||||
|
const dataset = createDataSet(defaultData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
dataset.group({ by: 'id' });
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dataset.grouping).toEqual({ by: 'id' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -39,10 +39,10 @@ export type Setter<T> =
|
||||||
export interface DataSet<T extends Record<string, any>> {
|
export interface DataSet<T extends Record<string, any>> {
|
||||||
data: T[];
|
data: T[];
|
||||||
nodes: Accessor<DataSetNode<keyof T, T>[]>;
|
nodes: Accessor<DataSetNode<keyof T, T>[]>;
|
||||||
value: Accessor<(T | undefined)[]>;
|
|
||||||
mutations: Accessor<Mutation[]>;
|
mutations: Accessor<Mutation[]>;
|
||||||
sorting: Accessor<SortOptions<T> | undefined>;
|
readonly value: (T | undefined)[];
|
||||||
grouping: Accessor<GroupOptions<T> | undefined>;
|
readonly sorting: SortOptions<T> | undefined;
|
||||||
|
readonly grouping: GroupOptions<T> | undefined;
|
||||||
|
|
||||||
mutate<K extends keyof T>(index: number, prop: K, value: T[K]): void;
|
mutate<K extends keyof T>(index: number, prop: K, value: T[K]): void;
|
||||||
mutateEach(setter: (value: T) => T): void;
|
mutateEach(setter: (value: T) => T): void;
|
||||||
|
@ -107,10 +107,16 @@ export const createDataSet = <T extends Record<string, any>>(data: T[], initialO
|
||||||
const set: DataSet<T> = {
|
const set: DataSet<T> = {
|
||||||
data,
|
data,
|
||||||
nodes,
|
nodes,
|
||||||
value: createMemo(() => state.value),
|
get value() {
|
||||||
|
return state.value;
|
||||||
|
},
|
||||||
mutations,
|
mutations,
|
||||||
sorting,
|
get sorting() {
|
||||||
grouping,
|
return state.sorting;
|
||||||
|
},
|
||||||
|
get grouping() {
|
||||||
|
return state.grouping;
|
||||||
|
},
|
||||||
|
|
||||||
mutate(index, prop, value) {
|
mutate(index, prop, value) {
|
||||||
setState('value', index, prop as any, value);
|
setState('value', index, prop as any, value);
|
||||||
|
|
15
src/components/table/table.spec.tsx
Normal file
15
src/components/table/table.spec.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { describe, it, expect } from 'bun:test';
|
||||||
|
import { render } from "@solidjs/testing-library"
|
||||||
|
import { Table } from './table';
|
||||||
|
import { createDataSet } from './dataset';
|
||||||
|
|
||||||
|
type TableItem = {};
|
||||||
|
|
||||||
|
// describe('<Table />', () => {
|
||||||
|
// it('should render', async () => {
|
||||||
|
// const dataset = createDataSet<TableItem>([]);
|
||||||
|
// const result = render(() => <Table rows={dataset} columns={[]} />);
|
||||||
|
|
||||||
|
// expect(true).toBe(true);
|
||||||
|
// });
|
||||||
|
// });
|
|
@ -166,7 +166,7 @@ function Head(props: {}) {
|
||||||
|
|
||||||
<For each={table.columns()}>{
|
<For each={table.columns()}>{
|
||||||
({ id, label, sortable }) => {
|
({ id, label, sortable }) => {
|
||||||
const sort = createMemo(() => table.rows().sorting());
|
const sort = createMemo(() => table.rows().sorting);
|
||||||
const by = String(id);
|
const by = String(id);
|
||||||
|
|
||||||
const onPointerDown = (e: PointerEvent) => {
|
const onPointerDown = (e: PointerEvent) => {
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function Grid(props: { class?: string, rows: Entry[], locales: string[],
|
||||||
id: lang,
|
id: lang,
|
||||||
label: lang,
|
label: lang,
|
||||||
renderer: ({ row, column, value, mutate }) => {
|
renderer: ({ row, column, value, mutate }) => {
|
||||||
const entry = rows().value()[row]!;
|
const entry = rows().value[row]!;
|
||||||
|
|
||||||
return <TextArea row={row} key={entry.key} lang={String(column)} value={value} oninput={e => mutate(e.data ?? '')} />;
|
return <TextArea row={row} key={entry.key} lang={String(column)} value={value} oninput={e => mutate(e.data ?? '')} />;
|
||||||
},
|
},
|
||||||
|
|
|
@ -265,7 +265,7 @@ describe('utilities', () => {
|
||||||
const actual = first(deepDiff(a, b));
|
const actual = first(deepDiff(a, b));
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
expect(actual).toEqual({ kind: MutarionKind.Delete, key: 'key' });
|
expect(actual).toEqual({ kind: MutarionKind.Delete, key: 'key', original: 'value' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should yield a mutation of type update when the value of a key in `a` is not equal to the value of the same key in `b`', async () => {
|
it('should yield a mutation of type update when the value of a key in `a` is not equal to the value of the same key in `b`', async () => {
|
||||||
|
@ -302,8 +302,8 @@ describe('utilities', () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
expect(actual).toEqual([
|
expect(actual).toEqual([
|
||||||
{ kind: MutarionKind.Delete, key: 'key2' },
|
{ kind: MutarionKind.Delete, key: 'key2', original: 'value2' },
|
||||||
{ kind: MutarionKind.Delete, key: 'key3' },
|
{ kind: MutarionKind.Delete, key: 'key3', original: 'value3' },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ describe('utilities', () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
expect(actual).toEqual([
|
expect(actual).toEqual([
|
||||||
{ kind: MutarionKind.Delete, key: 'key2_old' },
|
{ kind: MutarionKind.Delete, key: 'key2_old', original: 'value2' },
|
||||||
{ kind: MutarionKind.Create, key: 'key2_new', value: 'value2' },
|
{ kind: MutarionKind.Create, key: 'key2_new', value: 'value2' },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -361,7 +361,7 @@ describe('utilities', () => {
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
expect(actual).toEqual([
|
expect(actual).toEqual([
|
||||||
{ kind: MutarionKind.Delete, key: 'key.2' },
|
{ kind: MutarionKind.Delete, key: 'key.2', original: 2 },
|
||||||
{ kind: MutarionKind.Create, key: 'key.5', value: 5 },
|
{ kind: MutarionKind.Create, key: 'key.5', value: 5 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue