Skip to content
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
44 changes: 32 additions & 12 deletions apps/showcase-e2e/src/demos/button/as-link-button-demo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,78 @@ test.describe('As Link Button Demo', () => {
await page.goto('/demos/button/as-link-button-demo');
});

test('should render all three link buttons', async ({ page }) => {
const links = page.locator('a[sc-button]');
await expect(links).toHaveCount(3);
test('should render all six link buttons', async ({ page }) => {
const links = page.locator('a[sc-link]');
await expect(links).toHaveCount(6);
});

test('should use anchor elements instead of buttons', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
const tagName = await links.nth(i).evaluate((el) => el.tagName);
expect(tagName).toBe('A');
}
});

test('should not have type attribute on anchor elements', async ({ page }) => {
const links = page.locator('a[sc-button]');
test('should not have type attribute on anchor elements', async ({
page,
}) => {
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).not.toHaveAttribute('type');
}
});

test('should have href attributes', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).toHaveAttribute('href', '#');
}
});

test('should render Default Link', async ({ page }) => {
const link = page.getByRole('link', { name: 'Default Link' });
const link = page.getByRole('link', { name: 'Default' });
await expect(link).toBeVisible();
await expect(link).toHaveClass(/bg-primary/);
});

test('should render Outline Link', async ({ page }) => {
const link = page.getByRole('link', { name: 'Outline Link' });
const link = page.getByRole('link', { name: 'Outline' });
await expect(link).toBeVisible();
await expect(link).toHaveClass(/border-border/);
});

test('should render Secondary Link', async ({ page }) => {
const link = page.getByRole('link', { name: 'Secondary' });
await expect(link).toBeVisible();
await expect(link).toHaveClass(/bg-secondary/);
});

test('should render Ghost Link', async ({ page }) => {
const link = page.getByRole('link', { name: 'Ghost Link' });
const link = page.getByRole('link', { name: 'Ghost' });
await expect(link).toBeVisible();
});

test('should render Destructive Link', async ({ page }) => {
const link = page.getByRole('link', { name: 'Destructive' });
await expect(link).toBeVisible();
await expect(link).toHaveClass(/text-destructive/);
});

test('should render Link variant', async ({ page }) => {
const link = page.getByRole('link', { name: 'Link' });
await expect(link).toBeVisible();
await expect(link).toHaveClass(/underline-offset-4/);
});

test('should have data-slot attribute', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).toHaveAttribute('data-slot', 'button');
await expect(links.nth(i)).toHaveAttribute('data-slot', 'link');
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ test.describe('Disabled Link Button Demo', () => {
});

test('should render all four disabled link buttons', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
await expect(links).toHaveCount(4);
});

test('should have aria-disabled on all link buttons', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).toHaveAttribute('aria-disabled', 'true');
Expand Down Expand Up @@ -43,18 +43,18 @@ test.describe('Disabled Link Button Demo', () => {
});

test('should have reduced opacity when disabled', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
const opacity = await links.nth(i).evaluate(
(el) => window.getComputedStyle(el).opacity,
);
const opacity = await links
.nth(i)
.evaluate((el) => window.getComputedStyle(el).opacity);
expect(parseFloat(opacity)).toBeLessThan(1);
}
});

test('should use anchor elements', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
const tagName = await links.nth(i).evaluate((el) => el.tagName);
Expand All @@ -63,10 +63,10 @@ test.describe('Disabled Link Button Demo', () => {
});

test('should have data-slot attribute', async ({ page }) => {
const links = page.locator('a[sc-button]');
const links = page.locator('a[sc-link]');
const count = await links.count();
for (let i = 0; i < count; i++) {
await expect(links.nth(i)).toHaveAttribute('data-slot', 'button');
await expect(links.nth(i)).toHaveAttribute('data-slot', 'link');
}
});
});
151 changes: 151 additions & 0 deletions apps/showcase-e2e/src/demos/pagination/basic-pagination-demo.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { test, expect } from '@playwright/test';

test.describe('Basic Pagination Demo', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/demos/pagination/basic-pagination-demo');
});

test('should render pagination navigation', async ({ page }) => {
const nav = page.locator('nav[sc-pagination]');
await expect(nav).toBeVisible();
await expect(nav).toHaveAttribute('role', 'navigation');
await expect(nav).toHaveAttribute('aria-label', 'pagination');
await expect(nav).toHaveAttribute('data-slot', 'pagination');
});

test('should render pagination list', async ({ page }) => {
const list = page.locator('ul[sc-pagination-list]');
await expect(list).toBeVisible();
await expect(list).toHaveAttribute('data-slot', 'pagination-list');
});

test('should render Previous and Next buttons', async ({ page }) => {
const previousBtn = page.getByRole('button', { name: 'Previous' });
await expect(previousBtn).toBeVisible();
await expect(previousBtn).toHaveAttribute('data-slot', 'pagination-previous');

const nextBtn = page.getByRole('button', { name: 'Next' });
await expect(nextBtn).toBeVisible();
await expect(nextBtn).toHaveAttribute('data-slot', 'pagination-next');
});

test('should render page link buttons for 3 pages', async ({ page }) => {
const pageLinks = page.locator('button[sc-pagination-link]');
await expect(pageLinks).toHaveCount(3);

await expect(pageLinks.nth(0)).toHaveText(/1/);
await expect(pageLinks.nth(1)).toHaveText(/2/);
await expect(pageLinks.nth(2)).toHaveText(/3/);
});

test('should have aria-current on the active page', async ({ page }) => {
const activePage = page.locator(
'button[sc-pagination-link][aria-current="page"]',
);
await expect(activePage).toHaveCount(1);
await expect(activePage).toHaveText(/1/);
});

test('should apply outline variant to active page link', async ({
page,
}) => {
const activePage = page.locator(
'button[sc-pagination-link][aria-current="page"]',
);
await expect(activePage).toHaveClass(/border-border/);
});

test('should apply ghost variant to inactive page links', async ({
page,
}) => {
const inactiveLinks = page.locator(
'button[sc-pagination-link]:not([aria-current])',
);
const count = await inactiveLinks.count();
expect(count).toBeGreaterThan(0);
for (let i = 0; i < count; i++) {
await expect(inactiveLinks.nth(i)).toHaveClass(/hover:bg-muted/);
}
});

test('should disable Previous button on first page', async ({ page }) => {
const previousBtn = page.locator('button[sc-pagination-previous]');
await expect(previousBtn).toHaveAttribute('aria-disabled', 'true');
});

test('should not disable Next button on first page', async ({ page }) => {
const nextBtn = page.locator('button[sc-pagination-next]');
await expect(nextBtn).not.toHaveAttribute('aria-disabled');
});

test('should navigate to next page when clicking Next', async ({ page }) => {
const nextBtn = page.getByRole('button', { name: 'Next' });
await nextBtn.click();

const activePage = page.locator(
'button[sc-pagination-link][aria-current="page"]',
);
await expect(activePage).toHaveText(/2/);
});

test('should navigate to a specific page when clicking page link', async ({
page,
}) => {
const page3Btn = page.locator('button[sc-pagination-link]').nth(2);
await page3Btn.click();

const activePage = page.locator(
'button[sc-pagination-link][aria-current="page"]',
);
await expect(activePage).toHaveText(/3/);
});

test('should disable Next button on last page', async ({ page }) => {
const page3Btn = page.locator('button[sc-pagination-link]').nth(2);
await page3Btn.click();

const nextBtn = page.locator('button[sc-pagination-next]');
await expect(nextBtn).toHaveAttribute('aria-disabled', 'true');
});

test('should enable Previous button after navigating away from first page', async ({
page,
}) => {
const nextBtn = page.getByRole('button', { name: 'Next' });
await nextBtn.click();

const previousBtn = page.locator('button[sc-pagination-previous]');
await expect(previousBtn).not.toHaveAttribute('aria-disabled');
});

test('should render SVG icons in Previous and Next buttons', async ({
page,
}) => {
const previousSvg = page
.locator('button[sc-pagination-previous]')
.locator('svg');
await expect(previousSvg).toBeVisible();

const nextSvg = page.locator('button[sc-pagination-next]').locator('svg');
await expect(nextSvg).toBeVisible();
});

test('should have data-slot on pagination items', async ({ page }) => {
const items = page.locator('li[sc-pagination-item]');
const count = await items.count();
expect(count).toBeGreaterThan(0);
for (let i = 0; i < count; i++) {
await expect(items.nth(i)).toHaveAttribute('data-slot', 'pagination-item');
}
});

test('should be keyboard navigable', async ({ page }) => {
await page.keyboard.press('Tab');
const previousBtn = page.locator('button[sc-pagination-previous]');
await expect(previousBtn).toBeFocused();

await page.keyboard.press('Tab');
const firstPageLink = page.locator('button[sc-pagination-link]').first();
await expect(firstPageLink).toBeFocused();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { test, expect } from '@playwright/test';

test.describe('Buttons Pagination Demo', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/demos/pagination/buttons-pagination-demo');
});

test('should render pagination with button elements', async ({ page }) => {
const nav = page.locator('nav[sc-pagination]');
await expect(nav).toBeVisible();

const previousBtn = page.locator('button[sc-pagination-previous]');
await expect(previousBtn).toBeVisible();

const nextBtn = page.locator('button[sc-pagination-next]');
await expect(nextBtn).toBeVisible();
});

test('should use button elements for page links', async ({ page }) => {
const pageLinks = page.locator('button[sc-pagination-link]');
const count = await pageLinks.count();
expect(count).toBeGreaterThan(0);
for (let i = 0; i < count; i++) {
const tagName = await pageLinks.nth(i).evaluate((el) => el.tagName);
expect(tagName).toBe('BUTTON');
}
});

test('should use button elements for Previous and Next', async ({
page,
}) => {
const previousBtn = page.locator('button[sc-pagination-previous]');
const tagName = await previousBtn.evaluate((el) => el.tagName);
expect(tagName).toBe('BUTTON');

const nextBtn = page.locator('button[sc-pagination-next]');
const nextTagName = await nextBtn.evaluate((el) => el.tagName);
expect(nextTagName).toBe('BUTTON');
});

test('should not have href attributes on buttons', async ({ page }) => {
const pageLinks = page.locator('button[sc-pagination-link]');
const count = await pageLinks.count();
for (let i = 0; i < count; i++) {
await expect(pageLinks.nth(i)).not.toHaveAttribute('href');
}
});

test('should have data-slot attributes', async ({ page }) => {
const pageLinks = page.locator('button[sc-pagination-link]');
const count = await pageLinks.count();
for (let i = 0; i < count; i++) {
await expect(pageLinks.nth(i)).toHaveAttribute(
'data-slot',
'pagination-link',
);
}
});

test('should render 3 page links for 30 items with pageSize 10', async ({
page,
}) => {
const pageLinks = page.locator('button[sc-pagination-link]');
await expect(pageLinks).toHaveCount(3);
});

test('should navigate between pages using buttons', async ({ page }) => {
const page2 = page.locator('button[sc-pagination-link]', {
hasText: /^\s*2\s*$/,
});
await page2.click();

const activePage = page.locator(
'button[sc-pagination-link][aria-current="page"]',
);
await expect(activePage).toHaveText(/2/);

const page3 = page.locator('button[sc-pagination-link]', {
hasText: /^\s*3\s*$/,
});
await page3.click();

await expect(activePage).toHaveText(/3/);
});

test('should be keyboard accessible', async ({ page }) => {
await page.keyboard.press('Tab');
const previousBtn = page.locator('button[sc-pagination-previous]');
await expect(previousBtn).toBeFocused();

await page.keyboard.press('Tab');
const firstLink = page.locator('button[sc-pagination-link]').first();
await expect(firstLink).toBeFocused();

await page.keyboard.press('Enter');
await expect(firstLink).toHaveAttribute('aria-current', 'page');
});
});
Loading
Loading