Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stories and tests covering new DataTable features #73

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion modules/notifications/NotificationsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@
>
{(props) => (
<DataTableBasicView {...props}>
{(notification) => <Notification notification={notification} />}
{(rows) =>
rows.map((row) => {
const notification = row.original
return (
<Notification key={notification.id} notification={notification} />

Check warning on line 66 in modules/notifications/NotificationsTable/index.tsx

View check run for this annotation

Codecov / codecov/patch

modules/notifications/NotificationsTable/index.tsx#L62-L66

Added lines #L62 - L66 were not covered by tests
)
})

Check warning on line 68 in modules/notifications/NotificationsTable/index.tsx

View check run for this annotation

Codecov / codecov/patch

modules/notifications/NotificationsTable/index.tsx#L68

Added line #L68 was not covered by tests
}
</DataTableBasicView>
)}
</DataTable>
Expand Down
52 changes: 41 additions & 11 deletions packages/design-system/src/components/DataTable/DataTable.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,50 @@
import { createColumnHelper } from '@tanstack/react-table'

export const peopleData = [
{ name: 'John', age: 52 },
{ name: 'Doe', age: 19 },
{ name: 'Lorem', age: 24 },
{ name: 'Anna', age: 47 },
{ name: 'Mark', age: 18 },
{ name: 'Ralph', age: 12 },
{ name: 'Jasmine', age: 34 },
{
name: 'John',
age: 52,
updatedAt: new Date(2019, 1, 12, 23, 31),
},
{
name: 'Doe',
age: 19,
updatedAt: null,
},
{
name: 'Lorem',
age: 24,
updatedAt: new Date(2023, 6, 3, 12, 33),
},
{
name: 'Anna',
age: 47,
updatedAt: new Date(2022, 8, 24, 19, 11),
},
{
name: 'Mark',
age: 18,
updatedAt: null,
},
{
name: 'Ralph',
age: 12,
updatedAt: new Date(2016, 3, 7, 4, 17),
},
{
name: 'Jasmine',
age: 34,
updatedAt: new Date(2024, 0, 9, 3, 58),
},
]

export type Person = (typeof peopleData)[number]

export const columnHelper = createColumnHelper<Person>()

export const peopleColumns = [
columnHelper.accessor('name', { header: 'Name' }),
columnHelper.accessor('age', { header: 'Age' }),
]
export const peopleColumn = {
name: columnHelper.accessor('name', { header: 'Name' }),
age: columnHelper.accessor('age', { header: 'Age' }),
}

export const peopleColumns = [peopleColumn.name, peopleColumn.age]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@
//
import { type Meta, type StoryObj } from '@storybook/react'
import { DataTable } from './DataTable'
import { peopleColumns, peopleData, type Person } from './DataTable.mocks'
import { dateColumn, dateTimeColumn } from './DataTable.columns'
import {
peopleColumns,
peopleData,
type Person,
peopleColumn,
columnHelper,
} from './DataTable.mocks'
import { DataTableBasicView } from './DataTableBasicView'
import { Button } from '../Button'

const meta: Meta<typeof DataTable> = {
Expand Down Expand Up @@ -50,3 +58,78 @@ export const HeaderAction: Story = {
),
},
}

/**
* Click on row
* */
export const RowAction: Story = {
args: {
...Default.args,
tableView: {
onRowClick: (person) => alert(`Clicked row: ${person.name}`),
},
},
}

export const PremadeColumns: Story = {
args: {
...Default.args,
columns: [
peopleColumn.name,
columnHelper.accessor('updatedAt', {
header: 'Date',
cell: dateColumn,
}),
columnHelper.accessor('updatedAt', {
header: 'Date Time',
cell: dateTimeColumn,
}),
],
},
}

/**
* Custom view that replaces standard table view
* */
export const CustomView = () => (
<DataTable<Person>
columns={peopleColumns}
data={peopleData}
entityName="users"
className="m-5"
>
{(props) => (
<DataTableBasicView {...props}>
{(rows) => (
<div className="grid grid-cols-3 gap-4 p-4">
{rows.map((row) => {
const person = row.original
return (
<div key={row.id} className="flex flex-col border p-6">
<h4 className="text-lg font-medium">{person.name}</h4>
<span className="text-sm text-muted-foreground">
{person.age} years old
</span>
</div>
)
})}
</div>
)}
</DataTableBasicView>
)}
</DataTable>
)

export const Minimal: Story = {
args: {
...Default.args,
minimal: true,
},
}

export const NoBorder: Story = {
args: {
...Default.args,
bordered: false,
},
}
84 changes: 79 additions & 5 deletions packages/design-system/src/components/DataTable/DataTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { fireEvent, render, screen, within } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event'
import { peopleColumns, peopleData } from './DataTable.mocks'
import { DataTable } from '.'
import { DataTable, DataTableBasicView } from '.'

describe('DataTable', () => {
const getTBody = () => {
Expand All @@ -27,6 +27,12 @@ describe('DataTable', () => {
expect(cellColumn).toBeInTheDocument()
})

const expectEmptyStateToBeInTheDocument = () => {
// Regex because text is broken with elements
const emptyState = screen.getByText(/No\sresults\sfound/)
expect(emptyState).toBeInTheDocument()
}

it('renders table element with respective columns', () => {
render(<DataTable columns={peopleColumns} data={peopleData} />)

Expand All @@ -43,9 +49,7 @@ describe('DataTable', () => {
it('shows empty state', () => {
const { rerender } = render(<DataTable columns={peopleColumns} data={[]} />)

// Regex because text is broken with elements
const emptyState = screen.getByText(/No\sresults\sfound/)
expect(emptyState).toBeInTheDocument()
expectEmptyStateToBeInTheDocument()

rerender(<DataTable columns={peopleColumns} data={[]} entityName="users" />)
const emptyStateWithEntityName = screen.getByText(/No\susers\sfound/)
Expand Down Expand Up @@ -119,7 +123,6 @@ describe('DataTable', () => {
await user.clear(searchInput)
await user.type(searchInput, '1111')

//
const emptyState = await screen.findByText(/No results found/)
expect(emptyState).toBeInTheDocument()
const searchTextDisplayed = screen.getByText(/"1111"/)
Expand All @@ -142,4 +145,75 @@ describe('DataTable', () => {
const emptyState = await screen.findByText(/No users found/)
expect(emptyState).toBeInTheDocument()
})

describe('minimal', () => {
it('hides header', () => {
render(<DataTable columns={peopleColumns} data={peopleData} minimal />)

const searchInput = screen.queryByRole('textbox', { name: 'Search...' })
expect(searchInput).not.toBeInTheDocument()
})

it('hides pagination counter if no pagination to show', () => {
render(<DataTable columns={peopleColumns} data={peopleData} minimal />)

const paginationCounter = screen.queryByRole('1-7 of 7')
expect(paginationCounter).not.toBeInTheDocument()
})

it('shows pagination counter if paginated', () => {
render(
<DataTable
columns={peopleColumns}
data={peopleData}
minimal
pageSize={2}
/>,
)

const paginationCounter = screen.getByText('1-2 of 7')
expect(paginationCounter).toBeInTheDocument()
})
})

describe('custom view', () => {
it('renders people using custom view', () => {
render(
<DataTable columns={peopleColumns} data={peopleData}>
{(props) => (
<DataTableBasicView {...props}>
{(rows) =>
rows.map((row) => {
const person = row.original
return (
<div key={row.id} role="row">
Person name - {person.name}
</div>
)
})
}
</DataTableBasicView>
)}
</DataTable>,
)

const roles = screen.getAllByRole('row')
expect(roles).toHaveLength(peopleData.length)

const john = screen.getByText('Person name - John')
expect(john).toBeInTheDocument()
})

it('shows empty state', () => {
render(
<DataTable columns={peopleColumns} data={[]}>
{(props) => (
<DataTableBasicView {...props}>{() => null}</DataTableBasicView>
)}
</DataTable>,
)

expectEmptyStateToBeInTheDocument()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
// SPDX-License-Identifier: MIT
//
import { type Row } from '@tanstack/react-table'
import { Fragment, type ReactNode } from 'react'
import { type ReactNode } from 'react'
import { EmptyState } from '@/packages/design-system/src/components/EmptyState'
import { ensureString } from '@/packages/design-system/src/utils/misc'
import type { DataTableViewProps } from './DataTable'

interface DataTableBasicViewProps<Data> extends DataTableViewProps<Data> {
children: (data: Data, row: Row<Data>) => ReactNode
children: (rows: Array<Row<Data>>) => ReactNode
}

/**
* Handles basic states for custom DataTable views
*
* @example See `DataTable.stories#CustomView`
* */
export const DataTableBasicView = <Data,>({
table,
entityName,
Expand All @@ -30,10 +35,7 @@ export const DataTableBasicView = <Data,>({
hasFilters={table.getState().columnFilters.length > 0}
className="h-24"
/>
: rows.map((row) => (
<Fragment key={row.id}>{children(row.original, row)}</Fragment>
))
}
: children(rows)}
</div>
)
}
Loading