Skip to content

Commit 76ae0fe

Browse files
committed
test: expand test suites to achieve full coverage
1 parent a9b68e6 commit 76ae0fe

4 files changed

Lines changed: 452 additions & 1 deletion

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { render } from '@solidjs/testing-library';
2+
import { expect, describe, test, vi } from 'vitest';
3+
import { MetaProvider } from '@solidjs/meta';
4+
import type { JSX } from 'solid-js';
5+
import Head from './Head';
6+
7+
// Mock the AppConfig to avoid import issues
8+
vi.mock('@/constants/AppConfig', () => ({
9+
AppConfig: {
10+
title: 'Test Site',
11+
description: 'Test description',
12+
og: {
13+
image: {
14+
url: 'https://example.com/default-og-image.jpg'
15+
}
16+
}
17+
}
18+
}));
19+
20+
describe('Head component', () => {
21+
const renderWithMeta = (component: () => JSX.Element) => {
22+
return render(() => (
23+
<MetaProvider>
24+
{component()}
25+
</MetaProvider>
26+
));
27+
};
28+
29+
test('should render with default title and description', () => {
30+
const { unmount } = renderWithMeta(() => <Head />);
31+
32+
// Check if document head contains the expected meta tags
33+
expect(document.title).toBe('Test Site');
34+
35+
const metaDescription = document.querySelector('meta[name="description"]');
36+
expect(metaDescription?.getAttribute('content')).toBe('Test description');
37+
38+
unmount();
39+
});
40+
41+
test('should render with custom title and description', () => {
42+
const customTitle = 'Custom Page';
43+
const customDescription = 'Custom page description';
44+
45+
const { unmount } = renderWithMeta(() => (
46+
<Head title={customTitle} description={customDescription} />
47+
));
48+
49+
expect(document.title).toBe('Custom Page | Test Site');
50+
51+
const metaDescription = document.querySelector('meta[name="description"]');
52+
expect(metaDescription?.getAttribute('content')).toBe(customDescription);
53+
54+
unmount();
55+
});
56+
57+
test('should use website type when canonical is undefined', () => {
58+
const { unmount } = renderWithMeta(() => <Head />);
59+
60+
const ogType = document.querySelector('meta[property="og:type"]');
61+
expect(ogType?.getAttribute('content')).toBe('website');
62+
63+
unmount();
64+
});
65+
66+
test('should use article type when canonical is provided', () => {
67+
const { unmount } = renderWithMeta(() => <Head canonical="/test" />);
68+
69+
const ogType = document.querySelector('meta[property="og:type"]');
70+
expect(ogType?.getAttribute('content')).toBe('article');
71+
72+
unmount();
73+
});
74+
75+
test('should use custom OG image when provided', () => {
76+
const customOgImage = {
77+
og: {
78+
image: {
79+
url: '/custom-image.jpg'
80+
}
81+
}
82+
};
83+
84+
const { unmount } = renderWithMeta(() => <Head {...customOgImage} />);
85+
86+
const ogImage = document.querySelector('meta[property="og:image"]');
87+
// The actual implementation prepends siteUrl, but since siteUrl is empty in test, it just returns the path
88+
expect(ogImage?.getAttribute('content')).toContain('custom-image.jpg');
89+
90+
unmount();
91+
});
92+
93+
test('should use default OG image when custom image is not provided', () => {
94+
const { unmount } = renderWithMeta(() => <Head />);
95+
96+
const ogImage = document.querySelector('meta[property="og:image"]');
97+
expect(ogImage?.getAttribute('content')).toBe('https://example.com/default-og-image.jpg');
98+
99+
unmount();
100+
});
101+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { expect, describe, test } from 'vitest';
2+
import { formatDescription, buildCanonicalUrl } from './format';
3+
4+
describe('format utilities', () => {
5+
describe('formatDescription', () => {
6+
test('should remove HTML tags and truncate string', () => {
7+
const input = '<p>This is a <strong>test</strong> description with some HTML tags</p>';
8+
const result = formatDescription(input);
9+
10+
expect(result).toBe('This is a test description with some HTML tags');
11+
expect(result.length).toBeLessThanOrEqual(120);
12+
});
13+
14+
test('should remove newlines', () => {
15+
const input = 'Line 1\nLine 2\nLine 3';
16+
const result = formatDescription(input);
17+
18+
expect(result).toBe('Line 1Line 2Line 3');
19+
});
20+
21+
test('should truncate long descriptions to 120 characters or less', () => {
22+
const longText = 'a'.repeat(200);
23+
const result = formatDescription(longText);
24+
25+
// The actual implementation uses truncate package, which may add ellipsis
26+
expect(result.length).toBeLessThanOrEqual(123); // Account for possible ellipsis
27+
});
28+
});
29+
30+
describe('buildCanonicalUrl', () => {
31+
test('should build canonical URL with site URL', () => {
32+
const path = '/test-page';
33+
const result = buildCanonicalUrl(path);
34+
35+
// In test environment, siteUrl is empty, so result should just be the path
36+
expect(result).toBe('/test-page');
37+
});
38+
39+
test('should handle empty path', () => {
40+
const path = '';
41+
const result = buildCanonicalUrl(path);
42+
43+
expect(result).toBe('');
44+
});
45+
46+
test('should handle path with query parameters', () => {
47+
const path = '/page?param=value';
48+
const result = buildCanonicalUrl(path);
49+
50+
expect(result).toBe('/page?param=value');
51+
});
52+
});
53+
});
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { expect, describe, test } from 'vitest';
2+
import { sanitize, nl2br, sanitizeTextarea, escAttr } from './sanitize';
3+
4+
describe('sanitize utilities', () => {
5+
describe('sanitize', () => {
6+
test('should sanitize HTML while preserving safe tags', () => {
7+
const input = '<p>Safe content</p><script>alert("unsafe")</script>';
8+
const result = sanitize(input);
9+
10+
expect(result).toContain('<p>Safe content</p>');
11+
expect(result).not.toContain('<script>');
12+
});
13+
14+
test('should preserve target attribute', () => {
15+
const input = '<a href="#" target="_blank">Link</a>';
16+
const result = sanitize(input);
17+
18+
expect(result).toContain('target="_blank"');
19+
});
20+
});
21+
22+
describe('nl2br', () => {
23+
test('should convert newlines to <br> tags', () => {
24+
const input = 'Line 1\nLine 2\r\nLine 3\rLine 4';
25+
const result = nl2br(input);
26+
27+
expect(result).toBe('Line 1<br>Line 2<br>Line 3<br>Line 4');
28+
});
29+
30+
test('should handle empty string', () => {
31+
const result = nl2br('');
32+
expect(result).toBe('');
33+
});
34+
});
35+
36+
describe('sanitizeTextarea', () => {
37+
test('should sanitize and convert newlines', () => {
38+
const input = '<script>alert("test")</script>\nLine 2';
39+
const result = sanitizeTextarea(input);
40+
41+
expect(result).not.toContain('<script>');
42+
expect(result).toContain('<br>');
43+
});
44+
});
45+
46+
describe('escAttr', () => {
47+
test('should escape HTML entities and remove tags', () => {
48+
const input = '<script>alert("test")</script>&lt;test&gt;';
49+
const result = escAttr(input);
50+
51+
expect(result).not.toContain('<script>');
52+
expect(result).not.toContain('<');
53+
expect(result).not.toContain('>');
54+
});
55+
56+
test('should handle special characters', () => {
57+
const input = 'Test & "quotes" and \'apostrophes\'';
58+
const result = escAttr(input);
59+
60+
expect(result).toContain('&amp;');
61+
expect(result).toContain('&quot;');
62+
});
63+
64+
test('should handle empty string', () => {
65+
const result = escAttr('');
66+
expect(result).toBe('');
67+
});
68+
});
69+
});

0 commit comments

Comments
 (0)