135 lines
4.5 KiB
TypeScript
135 lines
4.5 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Blog Post — first-post (has heroImage, readTime, tags)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/blog/first-post/');
|
|
});
|
|
|
|
test('displays the post title', async ({ page }) => {
|
|
await expect(page.locator('h1.post-title')).toContainText('First post');
|
|
});
|
|
|
|
test('displays the post description as lede', async ({ page }) => {
|
|
await expect(page.locator('.post-lede')).toBeVisible();
|
|
});
|
|
|
|
test('displays the publication date', async ({ page }) => {
|
|
const time = page.locator('.post-meta time').first();
|
|
await expect(time).toBeVisible();
|
|
await expect(time).toHaveAttribute('datetime', /^\d{4}-/);
|
|
});
|
|
|
|
test('displays read time', async ({ page }) => {
|
|
await expect(page.locator('.meta-item.dim').first()).toContainText('min read');
|
|
});
|
|
|
|
test('displays tags', async ({ page }) => {
|
|
await expect(page.locator('.tag-row')).toBeVisible();
|
|
const tags = page.locator('.tag');
|
|
await expect(tags).toHaveCount(2); // Security, Meta
|
|
});
|
|
|
|
test('renders hero image', async ({ page }) => {
|
|
await expect(page.locator('.hero-image img')).toBeVisible();
|
|
});
|
|
|
|
test('renders post body content', async ({ page }) => {
|
|
await expect(page.locator('.prose')).not.toBeEmpty();
|
|
});
|
|
|
|
test('back link navigates to /blog', async ({ page }) => {
|
|
const backLink = page.getByRole('link', { name: /all articles/i });
|
|
await expect(backLink).toBeVisible();
|
|
await expect(backLink).toHaveAttribute('href', '/blog');
|
|
});
|
|
|
|
test('does NOT show updatedDate', async ({ page }) => {
|
|
await expect(page.locator('.meta-item').filter({ hasText: 'Updated' })).toHaveCount(0);
|
|
});
|
|
});
|
|
|
|
test.describe('Blog Post — using-mdx (MDX with embedded component)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/blog/using-mdx/');
|
|
});
|
|
|
|
test('displays the post title', async ({ page }) => {
|
|
await expect(page.locator('h1.post-title')).toContainText('Using MDX');
|
|
});
|
|
|
|
test('renders embedded HeaderLink component', async ({ page }) => {
|
|
const embeddedLink = page.getByRole('link', { name: /embedded component in mdx/i });
|
|
await expect(embeddedLink).toBeVisible();
|
|
});
|
|
|
|
test('displays MDX tags', async ({ page }) => {
|
|
await expect(page.locator('.tag-row')).toBeVisible();
|
|
await expect(page.locator('.tag').filter({ hasText: 'MDX' })).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Blog Post — test-fixture (no heroImage, no readTime, no tags; has updatedDate)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/blog/test-fixture/');
|
|
});
|
|
|
|
test('displays the post title', async ({ page }) => {
|
|
await expect(page.locator('h1.post-title')).toContainText('Test Fixture Post');
|
|
});
|
|
|
|
test('does NOT render a hero image', async ({ page }) => {
|
|
await expect(page.locator('.hero-image')).toHaveCount(0);
|
|
});
|
|
|
|
test('does NOT show a readTime entry', async ({ page }) => {
|
|
await expect(page.locator('.meta-item.dim').filter({ hasText: 'read' })).toHaveCount(0);
|
|
});
|
|
|
|
test('does NOT show tags section', async ({ page }) => {
|
|
await expect(page.locator('.tag-row')).toHaveCount(0);
|
|
});
|
|
|
|
test('shows updatedDate', async ({ page }) => {
|
|
// The "Updated" label appears in meta when updatedDate is present
|
|
await expect(page.locator('.meta-item').filter({ hasText: 'Updated' })).toBeVisible();
|
|
});
|
|
|
|
test('renders post body content', async ({ page }) => {
|
|
await expect(page.locator('.prose')).not.toBeEmpty();
|
|
});
|
|
});
|
|
|
|
test.describe('Blog Post — markdown-style-guide (rich markdown content)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/blog/markdown-style-guide/');
|
|
});
|
|
|
|
test('displays the post title', async ({ page }) => {
|
|
await expect(page.locator('h1.post-title')).toContainText('Markdown Style Guide');
|
|
});
|
|
|
|
test('renders a table in the post body', async ({ page }) => {
|
|
await expect(page.locator('.prose table')).toBeVisible();
|
|
});
|
|
|
|
test('renders code blocks', async ({ page }) => {
|
|
await expect(page.locator('.prose pre').first()).toBeVisible();
|
|
});
|
|
|
|
test('renders blockquote', async ({ page }) => {
|
|
await expect(page.locator('.prose blockquote').first()).toBeVisible();
|
|
});
|
|
});
|
|
|
|
test.describe('Blog Post — third-post (3 tags)', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/blog/third-post/');
|
|
});
|
|
|
|
test('shows 3 tags: Frontend, CSP, Security', async ({ page }) => {
|
|
await expect(page.locator('.tag').filter({ hasText: 'Frontend' })).toBeVisible();
|
|
await expect(page.locator('.tag').filter({ hasText: 'CSP' })).toBeVisible();
|
|
await expect(page.locator('.tag').filter({ hasText: 'Security' })).toBeVisible();
|
|
});
|
|
});
|