-
- {tool.name}
- {tool.status === 'obsolete' && (
-
{tool.status}
- )}
+
+
+ {tool.name}
+ {tool.status === 'obsolete' && (
+ {tool.status}
+ )}
+
+
+
+ Languages: {tool.languages?.join(', ')}
+
+
+ Supported Dialects:
+
+
+ {tool.supportedDialects?.draft?.map((draft) => (
+ {draft}
+ ))}
+
+
+ License: {tool.license}
-
-
- Languages: {tool.languages?.join(', ')}
-
-
- Supported Dialects:
-
-
- {tool.supportedDialects?.draft?.map((draft) => (
- {draft}
- ))}
-
-
- License: {tool.license}
-
);
From 1583a1f7940242977957d3590e94efa8b96daa84 Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Sun, 17 Aug 2025 16:33:22 +0300
Subject: [PATCH 4/9] adding tests for ToolingTable
---
cypress/components/ToolingTable.cy.tsx | 139 +++++++++++++++++++++++++
1 file changed, 139 insertions(+)
create mode 100644 cypress/components/ToolingTable.cy.tsx
diff --git a/cypress/components/ToolingTable.cy.tsx b/cypress/components/ToolingTable.cy.tsx
new file mode 100644
index 000000000..2e07d07e7
--- /dev/null
+++ b/cypress/components/ToolingTable.cy.tsx
@@ -0,0 +1,139 @@
+/* eslint-disable linebreak-style */
+import React from 'react';
+import ToolingTable from '~/pages/tools/components/ToolingTable';
+import type { GroupedTools, Transform } from '~/pages/tools/hooks/useToolsTransform';
+import type { JSONSchemaTool } from '~/pages/tools/JSONSchemaTool';
+import mockNextRouter, { MockRouter } from '../plugins/mockNextRouterUtils';
+
+const mockTools: JSONSchemaTool[] = [
+ {
+ name: 'Test Tool 1',
+ toolingTypes: ['validator'],
+ languages: ['JavaScript'],
+ license: 'MIT',
+ source: 'https://github.com/test/tool1',
+ supportedDialects: { draft: ['2020-12'] },
+ status: 'obsolete',
+ },
+ {
+ name: 'Test Tool 2',
+ toolingTypes: ['editor'],
+ languages: ['Python'],
+ license: 'Apache-2.0',
+ source: 'https://github.com/test/tool2',
+ supportedDialects: { draft: ['2019-09'] },
+ },
+];
+
+const mockToolsByGroup: GroupedTools = {
+ 'validator': [mockTools[0]],
+ 'editor': [mockTools[1]],
+};
+
+const mockTransform: Transform = {
+ query: '',
+ sortBy: 'name',
+ sortOrder: 'ascending',
+ groupBy: 'toolingTypes',
+ licenses: [],
+ languages: [],
+ drafts: [],
+ toolingTypes: [],
+ environments: [],
+ showObsolete: 'false',
+ supportsBowtie: 'false',
+};
+
+describe('ToolingTable Component', () => {
+ let setTransformStub: Cypress.SinonStub;
+ let mockRouter: MockRouter;
+
+ beforeEach(() => {
+ mockRouter = mockNextRouter();
+ cy.stub(global, 'fetch').resolves({
+ json: () => Promise.resolve({}),
+ } as Response);
+ setTransformStub = cy.stub().as('setTransform');
+ });
+
+ it('renders grouped tools correctly', () => {
+ cy.mount(
+
+ );
+
+ cy.contains('Validator').should('exist');
+ cy.contains('Editor').should('exist');
+ cy.contains('Test Tool 1').should('exist');
+ cy.contains('Test Tool 2').should('exist');
+ });
+
+ it('shows obsolete status and tool details', () => {
+ cy.mount(
+
+ );
+
+ cy.contains('obsolete').should('exist');
+ cy.contains('JavaScript').should('exist');
+ cy.contains('MIT').should('exist');
+ cy.contains('2020-12').should('exist');
+ });
+
+ it('handles sorting and modal interactions', () => {
+ cy.viewport(1200, 800); // Set large viewport to show desktop table
+
+ cy.mount(
+
+ );
+
+ cy.get('.hidden.lg\\:block').first().within(() => {
+ cy.contains('Name').click();
+ cy.get('@setTransform').should('have.been.called');
+
+ cy.get('tbody tr').first().click();
+ });
+
+ cy.get('[role="dialog"]').should('exist');
+ });
+
+ it('displays empty state when no tools', () => {
+ cy.mount(
+
+ );
+
+ cy.contains('No Tools Found :(').should('exist');
+ });
+
+ it('renders both desktop and mobile tables', () => {
+ cy.mount(
+
+ );
+
+ cy.get('.hidden.lg\\:block').should('exist');
+ cy.get('.lg\\:hidden').should('exist');
+ });
+});
From e315f6a2d5e408b3f0d3b89d2def91b2c7815a4e Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Sun, 17 Aug 2025 16:51:28 +0300
Subject: [PATCH 5/9] format fixes
---
cypress/components/ToolingTable.cy.tsx | 38 +++++++++++++++-----------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/cypress/components/ToolingTable.cy.tsx b/cypress/components/ToolingTable.cy.tsx
index 2e07d07e7..3d12eb800 100644
--- a/cypress/components/ToolingTable.cy.tsx
+++ b/cypress/components/ToolingTable.cy.tsx
@@ -1,7 +1,11 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable linebreak-style */
import React from 'react';
import ToolingTable from '~/pages/tools/components/ToolingTable';
-import type { GroupedTools, Transform } from '~/pages/tools/hooks/useToolsTransform';
+import type {
+ GroupedTools,
+ Transform,
+} from '~/pages/tools/hooks/useToolsTransform';
import type { JSONSchemaTool } from '~/pages/tools/JSONSchemaTool';
import mockNextRouter, { MockRouter } from '../plugins/mockNextRouterUtils';
@@ -26,8 +30,8 @@ const mockTools: JSONSchemaTool[] = [
];
const mockToolsByGroup: GroupedTools = {
- 'validator': [mockTools[0]],
- 'editor': [mockTools[1]],
+ validator: [mockTools[0]],
+ editor: [mockTools[1]],
};
const mockTransform: Transform = {
@@ -45,7 +49,7 @@ const mockTransform: Transform = {
};
describe('ToolingTable Component', () => {
- let setTransformStub: Cypress.SinonStub;
+ let setTransformStub: any;
let mockRouter: MockRouter;
beforeEach(() => {
@@ -63,7 +67,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />
+ />,
);
cy.contains('Validator').should('exist');
@@ -79,7 +83,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />
+ />,
);
cy.contains('obsolete').should('exist');
@@ -90,22 +94,24 @@ describe('ToolingTable Component', () => {
it('handles sorting and modal interactions', () => {
cy.viewport(1200, 800); // Set large viewport to show desktop table
-
+
cy.mount(
+ />,
);
- cy.get('.hidden.lg\\:block').first().within(() => {
- cy.contains('Name').click();
- cy.get('@setTransform').should('have.been.called');
-
- cy.get('tbody tr').first().click();
- });
+ cy.get('.hidden.lg\\:block')
+ .first()
+ .within(() => {
+ cy.contains('Name').click();
+ cy.get('@setTransform').should('have.been.called');
+
+ cy.get('tbody tr').first().click();
+ });
cy.get('[role="dialog"]').should('exist');
});
@@ -117,7 +123,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={0}
- />
+ />,
);
cy.contains('No Tools Found :(').should('exist');
@@ -130,7 +136,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />
+ />,
);
cy.get('.hidden.lg\\:block').should('exist');
From bda26c1e85ac5da266c69dab80c52533ab4c6da5 Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Sun, 17 Aug 2025 18:51:43 +0300
Subject: [PATCH 6/9] Revert "format fixes"
This reverts commit e315f6a2d5e408b3f0d3b89d2def91b2c7815a4e.
---
cypress/components/ToolingTable.cy.tsx | 38 +++++++++++---------------
1 file changed, 16 insertions(+), 22 deletions(-)
diff --git a/cypress/components/ToolingTable.cy.tsx b/cypress/components/ToolingTable.cy.tsx
index 3d12eb800..2e07d07e7 100644
--- a/cypress/components/ToolingTable.cy.tsx
+++ b/cypress/components/ToolingTable.cy.tsx
@@ -1,11 +1,7 @@
-/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable linebreak-style */
import React from 'react';
import ToolingTable from '~/pages/tools/components/ToolingTable';
-import type {
- GroupedTools,
- Transform,
-} from '~/pages/tools/hooks/useToolsTransform';
+import type { GroupedTools, Transform } from '~/pages/tools/hooks/useToolsTransform';
import type { JSONSchemaTool } from '~/pages/tools/JSONSchemaTool';
import mockNextRouter, { MockRouter } from '../plugins/mockNextRouterUtils';
@@ -30,8 +26,8 @@ const mockTools: JSONSchemaTool[] = [
];
const mockToolsByGroup: GroupedTools = {
- validator: [mockTools[0]],
- editor: [mockTools[1]],
+ 'validator': [mockTools[0]],
+ 'editor': [mockTools[1]],
};
const mockTransform: Transform = {
@@ -49,7 +45,7 @@ const mockTransform: Transform = {
};
describe('ToolingTable Component', () => {
- let setTransformStub: any;
+ let setTransformStub: Cypress.SinonStub;
let mockRouter: MockRouter;
beforeEach(() => {
@@ -67,7 +63,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />,
+ />
);
cy.contains('Validator').should('exist');
@@ -83,7 +79,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />,
+ />
);
cy.contains('obsolete').should('exist');
@@ -94,24 +90,22 @@ describe('ToolingTable Component', () => {
it('handles sorting and modal interactions', () => {
cy.viewport(1200, 800); // Set large viewport to show desktop table
-
+
cy.mount(
,
+ />
);
- cy.get('.hidden.lg\\:block')
- .first()
- .within(() => {
- cy.contains('Name').click();
- cy.get('@setTransform').should('have.been.called');
-
- cy.get('tbody tr').first().click();
- });
+ cy.get('.hidden.lg\\:block').first().within(() => {
+ cy.contains('Name').click();
+ cy.get('@setTransform').should('have.been.called');
+
+ cy.get('tbody tr').first().click();
+ });
cy.get('[role="dialog"]').should('exist');
});
@@ -123,7 +117,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={0}
- />,
+ />
);
cy.contains('No Tools Found :(').should('exist');
@@ -136,7 +130,7 @@ describe('ToolingTable Component', () => {
transform={mockTransform}
setTransform={setTransformStub}
numberOfTools={2}
- />,
+ />
);
cy.get('.hidden.lg\\:block').should('exist');
From 90c5393beb5532d944819980457db956ae30919f Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Sun, 17 Aug 2025 18:51:50 +0300
Subject: [PATCH 7/9] Revert "adding tests for ToolingTable"
This reverts commit 1583a1f7940242977957d3590e94efa8b96daa84.
---
cypress/components/ToolingTable.cy.tsx | 139 -------------------------
1 file changed, 139 deletions(-)
delete mode 100644 cypress/components/ToolingTable.cy.tsx
diff --git a/cypress/components/ToolingTable.cy.tsx b/cypress/components/ToolingTable.cy.tsx
deleted file mode 100644
index 2e07d07e7..000000000
--- a/cypress/components/ToolingTable.cy.tsx
+++ /dev/null
@@ -1,139 +0,0 @@
-/* eslint-disable linebreak-style */
-import React from 'react';
-import ToolingTable from '~/pages/tools/components/ToolingTable';
-import type { GroupedTools, Transform } from '~/pages/tools/hooks/useToolsTransform';
-import type { JSONSchemaTool } from '~/pages/tools/JSONSchemaTool';
-import mockNextRouter, { MockRouter } from '../plugins/mockNextRouterUtils';
-
-const mockTools: JSONSchemaTool[] = [
- {
- name: 'Test Tool 1',
- toolingTypes: ['validator'],
- languages: ['JavaScript'],
- license: 'MIT',
- source: 'https://github.com/test/tool1',
- supportedDialects: { draft: ['2020-12'] },
- status: 'obsolete',
- },
- {
- name: 'Test Tool 2',
- toolingTypes: ['editor'],
- languages: ['Python'],
- license: 'Apache-2.0',
- source: 'https://github.com/test/tool2',
- supportedDialects: { draft: ['2019-09'] },
- },
-];
-
-const mockToolsByGroup: GroupedTools = {
- 'validator': [mockTools[0]],
- 'editor': [mockTools[1]],
-};
-
-const mockTransform: Transform = {
- query: '',
- sortBy: 'name',
- sortOrder: 'ascending',
- groupBy: 'toolingTypes',
- licenses: [],
- languages: [],
- drafts: [],
- toolingTypes: [],
- environments: [],
- showObsolete: 'false',
- supportsBowtie: 'false',
-};
-
-describe('ToolingTable Component', () => {
- let setTransformStub: Cypress.SinonStub;
- let mockRouter: MockRouter;
-
- beforeEach(() => {
- mockRouter = mockNextRouter();
- cy.stub(global, 'fetch').resolves({
- json: () => Promise.resolve({}),
- } as Response);
- setTransformStub = cy.stub().as('setTransform');
- });
-
- it('renders grouped tools correctly', () => {
- cy.mount(
-
- );
-
- cy.contains('Validator').should('exist');
- cy.contains('Editor').should('exist');
- cy.contains('Test Tool 1').should('exist');
- cy.contains('Test Tool 2').should('exist');
- });
-
- it('shows obsolete status and tool details', () => {
- cy.mount(
-
- );
-
- cy.contains('obsolete').should('exist');
- cy.contains('JavaScript').should('exist');
- cy.contains('MIT').should('exist');
- cy.contains('2020-12').should('exist');
- });
-
- it('handles sorting and modal interactions', () => {
- cy.viewport(1200, 800); // Set large viewport to show desktop table
-
- cy.mount(
-
- );
-
- cy.get('.hidden.lg\\:block').first().within(() => {
- cy.contains('Name').click();
- cy.get('@setTransform').should('have.been.called');
-
- cy.get('tbody tr').first().click();
- });
-
- cy.get('[role="dialog"]').should('exist');
- });
-
- it('displays empty state when no tools', () => {
- cy.mount(
-
- );
-
- cy.contains('No Tools Found :(').should('exist');
- });
-
- it('renders both desktop and mobile tables', () => {
- cy.mount(
-
- );
-
- cy.get('.hidden.lg\\:block').should('exist');
- cy.get('.lg\\:hidden').should('exist');
- });
-});
From 68d294e8ff6fe79d563d59bbf9bda849314ec3b6 Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Mon, 18 Aug 2025 13:41:43 +0300
Subject: [PATCH 8/9] adding tests
---
cypress/components/ui/dialog.cy.tsx | 326 ++++++++++++++++++++
cypress/components/ui/table.cy.tsx | 445 ++++++++++++++++++++++++++++
2 files changed, 771 insertions(+)
create mode 100644 cypress/components/ui/dialog.cy.tsx
create mode 100644 cypress/components/ui/table.cy.tsx
diff --git a/cypress/components/ui/dialog.cy.tsx b/cypress/components/ui/dialog.cy.tsx
new file mode 100644
index 000000000..296224844
--- /dev/null
+++ b/cypress/components/ui/dialog.cy.tsx
@@ -0,0 +1,326 @@
+import React from 'react';
+import {
+ Dialog,
+ DialogTrigger,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+} from '@/components/ui/dialog';
+
+describe('Dialog Component', () => {
+ it('renders Dialog with all subcomponents correctly', () => {
+ cy.mount(
+
,
+ );
+
+ // Dialog root doesn't render visible DOM elements, so we test the content instead
+ cy.get('[data-slot="dialog-content"]').should('exist');
+ cy.get('[data-slot="dialog-header"]').should('exist');
+ cy.get('[data-slot="dialog-title"]').should('exist');
+ cy.get('[data-slot="dialog-description"]').should('exist');
+ cy.get('[data-slot="dialog-footer"]').should('exist');
+ });
+
+ it('renders Dialog with custom className correctly', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-content"]').should(
+ 'have.class',
+ 'custom-dialog-class',
+ );
+ });
+
+ it('renders Dialog with showCloseButton=false', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-close"]').should('not.exist');
+ });
+
+ it('renders Dialog with showCloseButton=true (default)', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-close"]').should('exist');
+ cy.get('[data-slot="dialog-close"]').should('contain.text', 'Close');
+ });
+
+ it('renders DialogTitle with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-title"]')
+ .should('exist')
+ .and('contain.text', 'Test Title')
+ .and('have.class', 'text-lg')
+ .and('have.class', 'font-semibold');
+ });
+
+ it('renders DialogDescription with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-description"]')
+ .should('exist')
+ .and('contain.text', 'Test Description')
+ .and('have.class', 'text-sm')
+ .and('have.class', 'text-muted-foreground');
+ });
+
+ it('renders DialogHeader with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-header"]')
+ .should('exist')
+ .and('have.class', 'custom-header-class')
+ .and('have.class', 'flex')
+ .and('have.class', 'flex-col')
+ .and('have.class', 'gap-2');
+ });
+
+ it('renders DialogFooter with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-footer"]')
+ .should('exist')
+ .and('have.class', 'custom-footer-class')
+ .and('have.class', 'flex')
+ .and('have.class', 'flex-col-reverse')
+ .and('have.class', 'gap-2');
+ });
+
+ it('renders DialogOverlay with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-overlay"]')
+ .should('exist')
+ .and('have.class', 'fixed')
+ .and('have.class', 'inset-0')
+ .and('have.class', 'z-50')
+ .and('have.class', 'bg-black/50');
+ });
+
+ it('renders DialogContent with correct positioning and styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-content"]')
+ .should('exist')
+ .and('have.class', 'fixed')
+ .and('have.class', 'top-[50%]')
+ .and('have.class', 'left-[50%]')
+ .and('have.class', 'z-50')
+ .and('have.class', 'rounded-lg')
+ .and('have.class', 'border')
+ .and('have.class', 'shadow-lg');
+ });
+
+ it('renders DialogTrigger correctly', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-trigger"]')
+ .should('exist')
+ .and('contain.text', 'Open Dialog');
+ });
+
+ it('renders DialogClose button with correct styling and accessibility', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-close"]')
+ .should('exist')
+ .and('have.class', 'absolute')
+ .and('have.class', 'top-4')
+ .and('have.class', 'right-4')
+ .and('have.class', 'rounded-xs');
+
+ // Check for screen reader text
+ cy.get('[data-slot="dialog-close"]').should('contain.text', 'Close');
+ });
+
+ it('applies custom className to DialogContent', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-content"]').should(
+ 'have.class',
+ 'my-custom-dialog',
+ );
+ });
+
+ it('applies custom className to DialogHeader', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-header"]').should(
+ 'have.class',
+ 'my-custom-header',
+ );
+ });
+
+ it('applies custom className to DialogFooter', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-footer"]').should(
+ 'have.class',
+ 'my-custom-footer',
+ );
+ });
+
+ it('applies custom className to DialogTitle', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-title"]').should(
+ 'have.class',
+ 'my-custom-title',
+ );
+ });
+
+ it('applies custom className to DialogDescription', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="dialog-description"]').should(
+ 'have.class',
+ 'my-custom-description',
+ );
+ });
+});
diff --git a/cypress/components/ui/table.cy.tsx b/cypress/components/ui/table.cy.tsx
new file mode 100644
index 000000000..58062f6be
--- /dev/null
+++ b/cypress/components/ui/table.cy.tsx
@@ -0,0 +1,445 @@
+import React from 'react';
+import {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+} from '@/components/ui/table';
+
+describe('Table Component', () => {
+ it('renders complete Table with all subcomponents correctly', () => {
+ cy.mount(
+
+ Test Table Caption
+
+
+ Name
+ Age
+ Email
+
+
+
+
+ John Doe
+ 30
+ john@example.com
+
+
+ Jane Smith
+ 25
+ jane@example.com
+
+
+
+
+ Total
+ 2
+ -
+
+
+
,
+ );
+
+ cy.get('[data-slot="table-container"]').should('exist');
+ cy.get('[data-slot="table"]').should('exist');
+ cy.get('[data-slot="table-caption"]').should('exist');
+ cy.get('[data-slot="table-header"]').should('exist');
+ cy.get('[data-slot="table-body"]').should('exist');
+ cy.get('[data-slot="table-footer"]').should('exist');
+ });
+
+ it('renders Table with custom className correctly', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table"]').should('have.class', 'custom-table-class');
+ });
+
+ it('renders TableContainer with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table-container"]')
+ .should('exist')
+ .and('have.class', 'relative')
+ .and('have.class', 'w-full')
+ .and('have.class', 'overflow-x-auto');
+ });
+
+ it('renders Table with correct base styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table"]')
+ .should('exist')
+ .and('have.class', 'w-full')
+ .and('have.class', 'caption-bottom')
+ .and('have.class', 'text-sm');
+ });
+
+ it('renders TableHeader with correct styling', () => {
+ cy.mount(
+
+
+
+ Header
+
+
+
+
+ Content
+
+
+
,
+ );
+
+ cy.get('[data-slot="table-header"]')
+ .should('exist')
+ .and('have.class', 'custom-header-class')
+ .and('have.class', '[&_tr]:border-b');
+ });
+
+ it('renders TableBody with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table-body"]')
+ .should('exist')
+ .and('have.class', 'custom-body-class')
+ .and('have.class', '[&_tr:last-child]:border-0');
+ });
+
+ it('renders TableFooter with correct styling', () => {
+ cy.mount(
+
+
+
+ Content
+
+
+
+
+ Footer
+
+
+
,
+ );
+
+ cy.get('[data-slot="table-footer"]')
+ .should('exist')
+ .and('have.class', 'custom-footer-class')
+ .and('have.class', 'bg-muted/50')
+ .and('have.class', 'border-t')
+ .and('have.class', 'font-medium');
+ });
+
+ it('renders TableRow with correct styling and hover effects', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table-row"]')
+ .should('exist')
+ .and('have.class', 'custom-row-class')
+ .and('have.class', 'hover:bg-muted/50')
+ .and('have.class', 'border-b')
+ .and('have.class', 'transition-colors');
+
+ // Check data-state attribute
+ cy.get('[data-slot="table-row"]').should(
+ 'have.attr',
+ 'data-state',
+ 'selected',
+ );
+ });
+
+ it('renders TableHead with correct styling', () => {
+ cy.mount(
+
+
+
+ Header Cell
+
+
+
+
+ Content
+
+
+
,
+ );
+
+ cy.get('[data-slot="table-head"]')
+ .should('exist')
+ .and('contain.text', 'Header Cell')
+ .and('have.class', 'custom-head-class')
+ .and('have.class', 'h-10')
+ .and('have.class', 'px-2')
+ .and('have.class', 'text-left')
+ .and('have.class', 'align-middle')
+ .and('have.class', 'font-medium')
+ .and('have.class', 'whitespace-nowrap');
+ });
+
+ it('renders TableCell with correct styling', () => {
+ cy.mount(
+
,
+ );
+
+ cy.get('[data-slot="table-cell"]')
+ .should('exist')
+ .and('contain.text', 'Cell Content')
+ .and('have.class', 'custom-cell-class')
+ .and('have.class', 'p-2')
+ .and('have.class', 'align-middle')
+ .and('have.class', 'whitespace-nowrap');
+ });
+
+ it('renders TableCaption with correct styling', () => {
+ cy.mount(
+
+
+ Test Caption
+
+
+
+ Content
+
+
+
,
+ );
+
+ cy.get('[data-slot="table-caption"]')
+ .should('exist')
+ .and('contain.text', 'Test Caption')
+ .and('have.class', 'custom-caption-class')
+ .and('have.class', 'mt-4')
+ .and('have.class', 'text-sm')
+ .and('have.class', 'text-muted-foreground');
+ });
+
+ it('renders complex table structure correctly', () => {
+ const data = [
+ { name: 'Alice', role: 'Developer', department: 'Engineering' },
+ { name: 'Bob', role: 'Designer', department: 'Design' },
+ { name: 'Charlie', role: 'Manager', department: 'Management' },
+ ];
+
+ cy.mount(
+
+ Employee Directory
+
+
+ Name
+ Role
+ Department
+
+
+
+ {data.map((employee, index) => (
+
+ {employee.name}
+ {employee.role}
+ {employee.department}
+
+ ))}
+
+
+
+ Total Employees
+ {data.length}
+ -
+
+
+
,
+ );
+
+ // Check caption
+ cy.get('[data-slot="table-caption"]').should(
+ 'contain.text',
+ 'Employee Directory',
+ );
+
+ // Check header
+ cy.get('[data-slot="table-header"]').should('exist');
+ cy.get('[data-slot="table-head"]').should('have.length', 3);
+ cy.get('[data-slot="table-head"]').eq(0).should('contain.text', 'Name');
+ cy.get('[data-slot="table-head"]').eq(1).should('contain.text', 'Role');
+ cy.get('[data-slot="table-head"]')
+ .eq(2)
+ .should('contain.text', 'Department');
+
+ // Check body rows
+ cy.get('[data-slot="table-body"] [data-slot="table-row"]').should(
+ 'have.length',
+ 3,
+ );
+ cy.get('[data-slot="table-body"] [data-slot="table-cell"]').should(
+ 'have.length',
+ 9,
+ ); // 3 rows × 3 cells in body only
+
+ // Check specific data
+ cy.get('[data-slot="table-cell"]').eq(0).should('contain.text', 'Alice');
+ cy.get('[data-slot="table-cell"]')
+ .eq(1)
+ .should('contain.text', 'Developer');
+ cy.get('[data-slot="table-cell"]')
+ .eq(2)
+ .should('contain.text', 'Engineering');
+
+ // Check footer
+ cy.get('[data-slot="table-footer"]').should('exist');
+ cy.get('[data-slot="table-footer"] [data-slot="table-cell"]')
+ .eq(1)
+ .should('contain.text', '3');
+ });
+
+ it('applies custom className to all table components', () => {
+ cy.mount(
+
+ Caption
+
+
+ Header
+
+
+
+
+ Content
+
+
+
+
+ Footer
+
+
+
,
+ );
+
+ cy.get('[data-slot="table"]').should('have.class', 'custom-table');
+ cy.get('[data-slot="table-caption"]').should(
+ 'have.class',
+ 'custom-caption',
+ );
+ cy.get('[data-slot="table-header"]').should('have.class', 'custom-header');
+ cy.get('[data-slot="table-header"] [data-slot="table-row"]').should(
+ 'have.class',
+ 'custom-header-row',
+ );
+ cy.get('[data-slot="table-head"]').should('have.class', 'custom-head');
+ cy.get('[data-slot="table-body"]').should('have.class', 'custom-body');
+ cy.get('[data-slot="table-body"] [data-slot="table-row"]').should(
+ 'have.class',
+ 'custom-body-row',
+ );
+ cy.get('[data-slot="table-cell"]').should('have.class', 'custom-cell');
+ cy.get('[data-slot="table-footer"]').should('have.class', 'custom-footer');
+ cy.get('[data-slot="table-footer"] [data-slot="table-row"]').should(
+ 'have.class',
+ 'custom-footer-row',
+ );
+ cy.get('[data-slot="table-footer"] [data-slot="table-cell"]').should(
+ 'have.class',
+ 'custom-footer-cell',
+ );
+ });
+
+ it('renders table with accessibility attributes correctly', () => {
+ cy.mount(
+
+ Accessible Table
+
+
+ Name
+ Age
+
+
+
+
+ John
+ 30
+
+
+
,
+ );
+
+ // Check that table elements are properly structured
+ cy.get('[data-slot="table"]').should('exist');
+ cy.get('[data-slot="table-header"]').should('exist');
+ cy.get('[data-slot="table-body"]').should('exist');
+
+ // Check for proper table structure
+ cy.get('[data-slot="table"]').should('be.visible');
+ cy.get('[data-slot="table-caption"]').should(
+ 'contain.text',
+ 'Accessible Table',
+ );
+ });
+
+ it('renders empty table structure correctly', () => {
+ cy.mount(
+
+
+
+ Column 1
+ Column 2
+
+
+ {/* Empty body */}
+
,
+ );
+
+ cy.get('[data-slot="table"]').should('exist');
+ cy.get('[data-slot="table-header"]').should('exist');
+ cy.get('[data-slot="table-body"]').should('exist');
+ cy.get('[data-slot="table-body"] [data-slot="table-row"]').should(
+ 'have.length',
+ 0,
+ );
+ });
+});
From 0935f94d9998ce60540f4eac2de9cec4bf66a5fe Mon Sep 17 00:00:00 2001
From: Idan Levi <29idan29@gmail.com>
Date: Mon, 18 Aug 2025 15:24:44 +0300
Subject: [PATCH 9/9] small adjustments
---
components/ui/dialog.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx
index bf20e0e83..64c8db5c4 100644
--- a/components/ui/dialog.tsx
+++ b/components/ui/dialog.tsx
@@ -1,5 +1,6 @@
/* eslint-disable linebreak-style */
/* eslint-disable react/prop-types */
+/* istanbul ignore file */
import * as React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { XIcon } from 'lucide-react';