mirror of
https://github.com/BradNut/personal-website-sveltekit
synced 2025-09-08 23:20:18 +00:00
Updating tests and removing test results
Some checks are pending
Run_Svelte_Unit_on_PRs / test (push) Waiting to run
Some checks are pending
Run_Svelte_Unit_on_PRs / test (push) Waiting to run
This commit is contained in:
parent
be24dac843
commit
9100958d4f
7 changed files with 393 additions and 18 deletions
2
.github/workflows/svelte_integration.yml
vendored
2
.github/workflows/svelte_integration.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
||||||
branches: [ main, master ]
|
branches: [ main, master ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main, master ]
|
branches: [ main, master ]
|
||||||
|
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
"bits-ui": "2.9.4",
|
"bits-ui": "2.9.4",
|
||||||
"flexsearch": "^0.8.205",
|
"flexsearch": "^0.8.205",
|
||||||
"ioredis": "^5.7.0",
|
"ioredis": "^5.7.0",
|
||||||
"lucide-svelte": "^0.541.0",
|
"lucide-svelte": "^0.542.0",
|
||||||
"scrape-it": "^6.1.11",
|
"scrape-it": "^6.1.11",
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"svelte-local-storage-store": "^0.6.4"
|
"svelte-local-storage-store": "^0.6.4"
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ importers:
|
||||||
specifier: ^5.7.0
|
specifier: ^5.7.0
|
||||||
version: 5.7.0
|
version: 5.7.0
|
||||||
lucide-svelte:
|
lucide-svelte:
|
||||||
specifier: ^0.541.0
|
specifier: ^0.542.0
|
||||||
version: 0.541.0(svelte@5.38.5)
|
version: 0.542.0(svelte@5.38.5)
|
||||||
scrape-it:
|
scrape-it:
|
||||||
specifier: ^6.1.11
|
specifier: ^6.1.11
|
||||||
version: 6.1.11
|
version: 6.1.11
|
||||||
|
|
@ -2077,8 +2077,8 @@ packages:
|
||||||
lower-case@2.0.2:
|
lower-case@2.0.2:
|
||||||
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
||||||
|
|
||||||
lucide-svelte@0.541.0:
|
lucide-svelte@0.542.0:
|
||||||
resolution: {integrity: sha512-Jk+LiOYDl62R/0nWkG1s5XL2k6LHmPq3wUfiJ6qtBhb8jGefB4PU10x5HJrAihwaKqVc2vH5wjKMELGjHJenEQ==}
|
resolution: {integrity: sha512-KxqJycY4EWaGy1zk/7sqEcf48j4YaP9zEujYczzrsw5j9b9b5pjAJ1qGFKZvD7T6xz9reSYAfUAd6Bz62TdqGw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^3 || ^4 || ^5.0.0-next.42
|
svelte: ^3 || ^4 || ^5.0.0-next.42
|
||||||
|
|
||||||
|
|
@ -4600,7 +4600,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
lucide-svelte@0.541.0(svelte@5.38.5):
|
lucide-svelte@0.542.0(svelte@5.38.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
svelte: 5.38.5
|
svelte: 5.38.5
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"status": "interrupted",
|
|
||||||
"failedTests": []
|
|
||||||
}
|
|
||||||
|
|
@ -31,12 +31,12 @@ test.describe('Home page', () => {
|
||||||
await expect(link).toBeVisible();
|
await expect(link).toBeVisible();
|
||||||
|
|
||||||
const before = await link.evaluate((el) => {
|
const before = await link.evaluate((el) => {
|
||||||
const cs = getComputedStyle(el as Element) as CSSStyleDeclaration;
|
const cs = getComputedStyle(el);
|
||||||
return { color: cs.color };
|
return { color: cs.color };
|
||||||
});
|
});
|
||||||
await link.hover();
|
await link.hover();
|
||||||
const after = await link.evaluate((el) => {
|
const after = await link.evaluate((el) => {
|
||||||
const cs = getComputedStyle(el as Element) as CSSStyleDeclaration;
|
const cs = getComputedStyle(el);
|
||||||
return { color: cs.color };
|
return { color: cs.color };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ test.describe('Home page', () => {
|
||||||
const nav = page.locator(area);
|
const nav = page.locator(area);
|
||||||
const link = nav.getByRole('link', { name: 'Home', exact: true });
|
const link = nav.getByRole('link', { name: 'Home', exact: true });
|
||||||
await expect(link).toBeVisible();
|
await expect(link).toBeVisible();
|
||||||
const isActive = await link.evaluate((el) => (el as Element).classList.contains('active'));
|
const isActive = await link.evaluate((el) => el.classList.contains('active'));
|
||||||
expect(isActive).toBeTruthy();
|
expect(isActive).toBeTruthy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -193,9 +193,9 @@ test.describe('Home page', () => {
|
||||||
|
|
||||||
// Layout: single column and scrollable vertically
|
// Layout: single column and scrollable vertically
|
||||||
const scrollInfo = await albumsGrid.evaluate((el) => ({
|
const scrollInfo = await albumsGrid.evaluate((el) => ({
|
||||||
overflowY: getComputedStyle(el as HTMLElement).overflowY,
|
overflowY: getComputedStyle(el).overflowY,
|
||||||
scrollHeight: (el as HTMLElement).scrollHeight,
|
scrollHeight: el.scrollHeight,
|
||||||
clientHeight: (el as HTMLElement).clientHeight,
|
clientHeight: el.clientHeight,
|
||||||
}));
|
}));
|
||||||
expect(scrollInfo.clientHeight).toBeLessThan(scrollInfo.scrollHeight);
|
expect(scrollInfo.clientHeight).toBeLessThan(scrollInfo.scrollHeight);
|
||||||
expect(['auto', 'scroll']).toContain(scrollInfo.overflowY);
|
expect(['auto', 'scroll']).toContain(scrollInfo.overflowY);
|
||||||
|
|
@ -216,7 +216,7 @@ test.describe('Home page', () => {
|
||||||
|
|
||||||
// Articles are a vertical list (same x, increasing y)
|
// Articles are a vertical list (same x, increasing y)
|
||||||
const boxes = await page.locator('section.articles article.card').evaluateAll((els) =>
|
const boxes = await page.locator('section.articles article.card').evaluateAll((els) =>
|
||||||
(els as HTMLElement[]).slice(0, Math.min(4, els.length)).map((el) => el.getBoundingClientRect())
|
els.slice(0, Math.min(4, els.length)).map((el) => el.getBoundingClientRect())
|
||||||
);
|
);
|
||||||
expect(boxes.length).toBeGreaterThan(0);
|
expect(boxes.length).toBeGreaterThan(0);
|
||||||
const x0 = boxes[0].left;
|
const x0 = boxes[0].left;
|
||||||
|
|
|
||||||
188
tests/portfolio.test.ts
Normal file
188
tests/portfolio.test.ts
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Portfolio page', () => {
|
||||||
|
test('has expected main heading', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
await expect(page.getByRole('heading', { level: 1, name: 'Portfolio!' })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('header/footer links hover: color becomes shellYellow', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
|
||||||
|
const shellYellow = await page.evaluate(() => {
|
||||||
|
const probe = document.createElement('div');
|
||||||
|
probe.style.color = 'var(--shellYellow)';
|
||||||
|
document.body.appendChild(probe);
|
||||||
|
const color = getComputedStyle(probe).color;
|
||||||
|
probe.remove();
|
||||||
|
return color;
|
||||||
|
});
|
||||||
|
|
||||||
|
const areas = [
|
||||||
|
'header[aria-label="header navigation"]',
|
||||||
|
'footer nav[aria-label="footer navigation"]',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const area of areas) {
|
||||||
|
const nav = page.locator(area);
|
||||||
|
await expect(nav).toBeVisible();
|
||||||
|
|
||||||
|
const link = nav.getByRole('link', { name: 'Portfolio', exact: true });
|
||||||
|
await expect(link).toBeVisible();
|
||||||
|
|
||||||
|
const before = await link.evaluate((el) => getComputedStyle(el as Element).color);
|
||||||
|
await link.hover();
|
||||||
|
const after = await link.evaluate((el) => getComputedStyle(el as Element).color);
|
||||||
|
|
||||||
|
expect(after).toBe(shellYellow);
|
||||||
|
expect(after).not.toBe(before);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('current page (Portfolio) link is active in header and footer', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
const areas = [
|
||||||
|
'header[aria-label="header navigation"]',
|
||||||
|
'footer nav[aria-label="footer navigation"]',
|
||||||
|
];
|
||||||
|
for (const area of areas) {
|
||||||
|
const nav = page.locator(area);
|
||||||
|
const portfolioLink = nav.getByRole('link', { name: 'Portfolio', exact: true });
|
||||||
|
await expect(portfolioLink).toBeVisible();
|
||||||
|
const isActive = await portfolioLink.evaluate((el) => (el as Element).classList.contains('active'));
|
||||||
|
expect(isActive).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('tabs render and can switch between Personal and Professional', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
|
||||||
|
// Prefer role-based tab selection; fall back to data attribute if role is not present
|
||||||
|
const personalTab = page.getByRole('tab', { name: 'Personal' }).or(page.locator('[data-tabs-trigger]', { hasText: 'Personal' }));
|
||||||
|
const professionalTab = page.getByRole('tab', { name: 'Professional' }).or(page.locator('[data-tabs-trigger]', { hasText: 'Professional' }));
|
||||||
|
|
||||||
|
await expect(personalTab).toBeVisible();
|
||||||
|
await expect(professionalTab).toBeVisible();
|
||||||
|
|
||||||
|
// Personal content visible by default (card heading exists)
|
||||||
|
const personalCardHeading = page.locator('.portfolio-picture h2', { hasText: 'Personal Website' }).first();
|
||||||
|
await expect(personalCardHeading).toBeVisible();
|
||||||
|
|
||||||
|
// Switch to Professional
|
||||||
|
await professionalTab.click();
|
||||||
|
|
||||||
|
// Professional content appears, personal may hide
|
||||||
|
const professionalCardHeading = page.locator('.portfolio-picture h2', { hasText: 'Mark Shellnut Architect' }).first();
|
||||||
|
await expect(professionalCardHeading).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('personal tab: key cards, images, and external links are accessible', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
|
||||||
|
// Ensure on Personal tab
|
||||||
|
const personalTab = page.getByRole('tab', { name: 'Personal' }).or(page.locator('[data-tabs-trigger]', { hasText: 'Personal' }));
|
||||||
|
await personalTab.click();
|
||||||
|
|
||||||
|
// Headings (scoped to portfolio cards to avoid strict-mode conflicts)
|
||||||
|
await expect(page.locator('.portfolio-picture h2', { hasText: 'Personal Website' }).first()).toBeVisible();
|
||||||
|
await expect(page.locator('.portfolio-picture h2', { hasText: 'Wedding Website' }).first()).toBeVisible();
|
||||||
|
await expect(page.locator('.portfolio-picture h2', { hasText: 'Old Personal Website' }).first()).toBeVisible();
|
||||||
|
|
||||||
|
// Images by alt text
|
||||||
|
await expect(page.getByAltText("Picture of Bradley Shellnut's Personal Website")).toBeVisible();
|
||||||
|
await expect(page.getByAltText('Picture of NextJS Wedding Website')).toBeVisible();
|
||||||
|
await expect(page.getByAltText('Home Page of the old bradleyshellnut.com website')).toBeVisible();
|
||||||
|
|
||||||
|
// External links (use visible link names)
|
||||||
|
await expect(page.getByRole('link', { name: /GitHub repository/i }).first()).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('professional tab: card renders with external link', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
|
||||||
|
const professionalTab = page.getByRole('tab', { name: 'Professional' }).or(page.locator('[data-tabs-trigger]', { hasText: 'Professional' }));
|
||||||
|
await professionalTab.click();
|
||||||
|
|
||||||
|
const professionalCard = page
|
||||||
|
.locator('.portfolio')
|
||||||
|
.filter({ has: page.locator('.portfolio-picture h2', { hasText: 'Mark Shellnut Architect' }) })
|
||||||
|
.first();
|
||||||
|
|
||||||
|
await expect(professionalCard).toBeVisible();
|
||||||
|
// Accessible name derived from aria-label in ExternalLink.svelte
|
||||||
|
await expect(
|
||||||
|
professionalCard.getByRole('link', { name: /Open\s+View Mark Shellnut Architect\s+externally/i })
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mirror header link presence from other pages
|
||||||
|
test('header navigation shows expected links', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
const headerNav = page.locator('header[aria-label="header navigation"]');
|
||||||
|
await expect(headerNav).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Home', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'About', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Portfolio', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Uses', exact: true })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mirror navigation flow via header (starting on /portfolio)
|
||||||
|
test('header navigation links go to correct routes (from /portfolio)', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
const headerNav = page.locator('header[aria-label="header navigation"]');
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'About', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/about\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Uses', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/uses\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Home', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Portfolio', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/portfolio\/?$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mirror footer link presence from other pages
|
||||||
|
test('footer shows expected links', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
const footerNav = page.getByRole('navigation', { name: 'footer navigation' });
|
||||||
|
await expect(footerNav).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Home', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'About', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Portfolio', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Uses', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Privacy', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Favorite Articles', exact: true })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mirror navigation via footer (starting on /portfolio)
|
||||||
|
test('footer navigation links go to correct routes (from /portfolio)', async ({ page }) => {
|
||||||
|
await page.goto('/portfolio');
|
||||||
|
const footerNav = page.getByRole('navigation', { name: 'footer navigation' });
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'Privacy', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'Privacy', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/privacy\/?$/);
|
||||||
|
|
||||||
|
// Favorite Articles may route to /articles or /articles/1
|
||||||
|
const fav = footerNav.getByRole('link', { name: 'Favorite Articles', exact: true });
|
||||||
|
await fav.scrollIntoViewIfNeeded();
|
||||||
|
const href = await fav.getAttribute('href');
|
||||||
|
expect(href).toBeTruthy();
|
||||||
|
if (href) {
|
||||||
|
expect(href).toMatch(/\/articles(\/\d+)?\/?$/);
|
||||||
|
await page.goto(href);
|
||||||
|
await expect(page).toHaveURL(/\/articles(\/\d+)?\/?$/, { timeout: 15000 });
|
||||||
|
}
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'About', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'About', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/about\/?$/);
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'Home', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'Home', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/?$/);
|
||||||
|
});
|
||||||
|
});
|
||||||
191
tests/uses.test.ts
Normal file
191
tests/uses.test.ts
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
|
test.describe('Uses page', () => {
|
||||||
|
test('has expected main heading', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
await expect(page.getByRole('heading', { level: 1, name: '/Uses' })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('header/footer links hover: color becomes shellYellow', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
|
||||||
|
const shellYellow = await page.evaluate(() => {
|
||||||
|
const probe = document.createElement('div');
|
||||||
|
probe.style.color = 'var(--shellYellow)';
|
||||||
|
document.body.appendChild(probe);
|
||||||
|
const color = getComputedStyle(probe).color;
|
||||||
|
probe.remove();
|
||||||
|
return color;
|
||||||
|
});
|
||||||
|
|
||||||
|
const areas = [
|
||||||
|
'header[aria-label="header navigation"]',
|
||||||
|
'footer nav[aria-label="footer navigation"]',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const area of areas) {
|
||||||
|
const nav = page.locator(area);
|
||||||
|
await expect(nav).toBeVisible();
|
||||||
|
|
||||||
|
const link = nav.getByRole('link', { name: 'Uses', exact: true });
|
||||||
|
await expect(link).toBeVisible();
|
||||||
|
|
||||||
|
const before = await link.evaluate((el) => getComputedStyle(el as Element).color);
|
||||||
|
await link.hover();
|
||||||
|
const after = await link.evaluate((el) => getComputedStyle(el as Element).color);
|
||||||
|
|
||||||
|
expect(after).toBe(shellYellow);
|
||||||
|
expect(after).not.toBe(before);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('current page (Uses) link is active in header and footer', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
const areas = [
|
||||||
|
'header[aria-label="header navigation"]',
|
||||||
|
'footer nav[aria-label="footer navigation"]',
|
||||||
|
];
|
||||||
|
for (const area of areas) {
|
||||||
|
const nav = page.locator(area);
|
||||||
|
const usesLink = nav.getByRole('link', { name: 'Uses', exact: true });
|
||||||
|
await expect(usesLink).toBeVisible();
|
||||||
|
const isActive = await usesLink.evaluate((el) => (el as Element).classList.contains('active'));
|
||||||
|
expect(isActive).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hero image visible with correct alt text', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
await expect(page.getByAltText('Clean desk with Samsung monitor and Ducky Keyboard')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('intro external links are accessible by aria-label-based names', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
|
||||||
|
// ExternalLink.svelte sets accessible name as: "Open {ariaLabel|title|href} externally"
|
||||||
|
await expect(page.getByRole('link', { name: /Open\s+Wes Bos' Website\s+externally/i })).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: /Open\s+Wes Bos' Uses Page\s+externally/i })).toBeVisible();
|
||||||
|
await expect(page.getByRole('link', { name: /Open\s+Uses\.tech\s+externally/i })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sections and subsections render', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
|
||||||
|
await expect(page.getByRole('heading', { level: 2, name: 'Development' })).toBeVisible();
|
||||||
|
|
||||||
|
// h3 subsections in development.svelte
|
||||||
|
const subsections = [
|
||||||
|
'Terminal & Shell Setup',
|
||||||
|
'Useful System Packages',
|
||||||
|
'Software',
|
||||||
|
'Useful Applications',
|
||||||
|
'Browsers',
|
||||||
|
];
|
||||||
|
for (const name of subsections) {
|
||||||
|
await expect(page.getByRole('heading', { level: 3, name })).toBeVisible();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('a few key external links in Development section are present', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
|
||||||
|
// Select within the Development section to be robust
|
||||||
|
const devSection = page.locator('section#uses-development');
|
||||||
|
await expect(devSection).toBeVisible();
|
||||||
|
|
||||||
|
const expectedLinks = [
|
||||||
|
/Open\s+Bradley Shellnut Computer Setup\s+externally/i,
|
||||||
|
/Open\s+Dotfiles\s+externally/i,
|
||||||
|
/Open\s+Tabby\s+externally/i,
|
||||||
|
/Open\s+Starship\s+externally/i,
|
||||||
|
/Open\s+ZimFW\s+externally/i,
|
||||||
|
/Open\s+Linux Brew\s+externally/i,
|
||||||
|
/Open\s+Homebrew\s+externally/i,
|
||||||
|
/Open\s+TLDR Man Pages\s+externally/i,
|
||||||
|
/Open\s+Trash-CLI\s+externally/i,
|
||||||
|
/Open\s+VSCodium\s+externally/i,
|
||||||
|
/Open\s+VSCode Extensions List\s+externally/i,
|
||||||
|
/Open\s+Sublime Text 3\s+externally/i,
|
||||||
|
/Open\s+Sublime Text Packages List\s+externally/i,
|
||||||
|
/Open\s+IntelliJ IDEA\s+externally/i,
|
||||||
|
/Open\s+IntelliJ Plugins\s+externally/i,
|
||||||
|
/Open\s+Bruno\s+externally/i,
|
||||||
|
/Open\s+Brave Browser\s+externally/i,
|
||||||
|
/Open\s+Firefox\s+externally/i,
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const pattern of expectedLinks) {
|
||||||
|
await expect(devSection.getByRole('link', { name: pattern })).toBeVisible();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Header nav presence
|
||||||
|
test('header navigation shows expected links', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
const headerNav = page.locator('header[aria-label="header navigation"]');
|
||||||
|
await expect(headerNav).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Home', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'About', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Portfolio', exact: true })).toBeVisible();
|
||||||
|
await expect(headerNav.getByRole('link', { name: 'Uses', exact: true })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Header navigation flow (starting on /uses)
|
||||||
|
test('header navigation links go to correct routes (from /uses)', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
const headerNav = page.locator('header[aria-label="header navigation"]');
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'About', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/about\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Portfolio', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/portfolio\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Home', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/?$/);
|
||||||
|
|
||||||
|
await headerNav.getByRole('link', { name: 'Uses', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/uses\/?$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Footer link presence
|
||||||
|
test('footer shows expected links', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
const footerNav = page.getByRole('navigation', { name: 'footer navigation' });
|
||||||
|
await expect(footerNav).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Home', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'About', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Portfolio', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Uses', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Privacy', exact: true })).toBeVisible();
|
||||||
|
await expect(footerNav.getByRole('link', { name: 'Favorite Articles', exact: true })).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Footer navigation flow (starting on /uses)
|
||||||
|
test('footer navigation links go to correct routes (from /uses)', async ({ page }) => {
|
||||||
|
await page.goto('/uses');
|
||||||
|
const footerNav = page.getByRole('navigation', { name: 'footer navigation' });
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'Privacy', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'Privacy', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/privacy\/?$/);
|
||||||
|
|
||||||
|
const fav = footerNav.getByRole('link', { name: 'Favorite Articles', exact: true });
|
||||||
|
await fav.scrollIntoViewIfNeeded();
|
||||||
|
const href = await fav.getAttribute('href');
|
||||||
|
expect(href).toBeTruthy();
|
||||||
|
if (href) {
|
||||||
|
expect(href).toMatch(/\/articles(\/\d+)?\/?$/);
|
||||||
|
await page.goto(href);
|
||||||
|
await expect(page).toHaveURL(/\/articles(\/\d+)?\/?$/, { timeout: 15000 });
|
||||||
|
}
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'About', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'About', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/about\/?$/);
|
||||||
|
|
||||||
|
await footerNav.getByRole('link', { name: 'Home', exact: true }).scrollIntoViewIfNeeded();
|
||||||
|
await footerNav.getByRole('link', { name: 'Home', exact: true }).click();
|
||||||
|
await expect(page).toHaveURL(/\/?$/);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue