@alliance-droid/svelte-docs-system 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +365 -0
- package/COVERAGE_REPORT.md +663 -0
- package/README.md +42 -0
- package/SEARCH_VERIFICATION.md +229 -0
- package/TEST_SUMMARY.md +344 -0
- package/bin/init.js +821 -0
- package/docs/E2E_TESTS.md +354 -0
- package/docs/TESTING.md +754 -0
- package/docs/de/index.md +41 -0
- package/docs/en/COMPONENTS.md +443 -0
- package/docs/en/api/examples.md +100 -0
- package/docs/en/api/overview.md +69 -0
- package/docs/en/components/index.md +622 -0
- package/docs/en/config/navigation.md +505 -0
- package/docs/en/config/theme-and-colors.md +395 -0
- package/docs/en/getting-started/integration.md +406 -0
- package/docs/en/guides/common-setups.md +651 -0
- package/docs/en/index.md +243 -0
- package/docs/en/markdown.md +102 -0
- package/docs/en/routing.md +64 -0
- package/docs/en/setup.md +52 -0
- package/docs/en/troubleshooting.md +704 -0
- package/docs/es/index.md +41 -0
- package/docs/fr/index.md +41 -0
- package/docs/ja/index.md +41 -0
- package/package.json +40 -0
- package/pagefind.toml +8 -0
- package/postcss.config.js +5 -0
- package/src/app.css +119 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +11 -0
- package/src/lib/assets/favicon.svg +1 -0
- package/src/lib/components/APITable.svelte +120 -0
- package/src/lib/components/APITable.test.ts +153 -0
- package/src/lib/components/Breadcrumbs.svelte +85 -0
- package/src/lib/components/Breadcrumbs.test.ts +148 -0
- package/src/lib/components/Callout.svelte +60 -0
- package/src/lib/components/Callout.test.ts +100 -0
- package/src/lib/components/CodeBlock.svelte +68 -0
- package/src/lib/components/CodeBlock.test.ts +133 -0
- package/src/lib/components/DocLayout.svelte +84 -0
- package/src/lib/components/Footer.svelte +78 -0
- package/src/lib/components/Image.svelte +100 -0
- package/src/lib/components/Image.test.ts +163 -0
- package/src/lib/components/Navbar.svelte +141 -0
- package/src/lib/components/Search.svelte +248 -0
- package/src/lib/components/Sidebar.svelte +110 -0
- package/src/lib/components/Tabs.svelte +48 -0
- package/src/lib/components/Tabs.test.ts +102 -0
- package/src/lib/config.test.ts +140 -0
- package/src/lib/config.ts +179 -0
- package/src/lib/configIntegration.test.ts +272 -0
- package/src/lib/configLoader.ts +231 -0
- package/src/lib/configParser.test.ts +217 -0
- package/src/lib/configParser.ts +234 -0
- package/src/lib/index.ts +34 -0
- package/src/lib/integration.test.ts +426 -0
- package/src/lib/navigationBuilder.test.ts +338 -0
- package/src/lib/navigationBuilder.ts +268 -0
- package/src/lib/performance.test.ts +369 -0
- package/src/lib/routing.test.ts +202 -0
- package/src/lib/routing.ts +127 -0
- package/src/lib/search-functionality.test.ts +493 -0
- package/src/lib/stores/i18n.test.ts +180 -0
- package/src/lib/stores/i18n.ts +143 -0
- package/src/lib/stores/nav.ts +36 -0
- package/src/lib/stores/search.test.ts +140 -0
- package/src/lib/stores/search.ts +162 -0
- package/src/lib/stores/theme.ts +59 -0
- package/src/lib/stores/version.test.ts +139 -0
- package/src/lib/stores/version.ts +111 -0
- package/src/lib/themeCustomization.test.ts +223 -0
- package/src/lib/themeCustomization.ts +212 -0
- package/src/lib/utils/highlight.test.ts +136 -0
- package/src/lib/utils/highlight.ts +100 -0
- package/src/lib/utils/index.ts +7 -0
- package/src/lib/utils/markdown.test.ts +357 -0
- package/src/lib/utils/markdown.ts +77 -0
- package/src/routes/+layout.server.ts +1 -0
- package/src/routes/+layout.svelte +28 -0
- package/src/routes/+page.svelte +165 -0
- package/static/robots.txt +3 -0
- package/svelte.config.js +18 -0
- package/tailwind.config.ts +55 -0
- package/template-starter/.github/workflows/build.yml +40 -0
- package/template-starter/.github/workflows/deploy-github-pages.yml +47 -0
- package/template-starter/.github/workflows/deploy-netlify.yml +41 -0
- package/template-starter/.github/workflows/deploy-vercel.yml +64 -0
- package/template-starter/NPM-PACKAGE-SETUP.md +233 -0
- package/template-starter/README.md +320 -0
- package/template-starter/docs/_config.json +39 -0
- package/template-starter/docs/api/components.md +257 -0
- package/template-starter/docs/api/overview.md +169 -0
- package/template-starter/docs/guides/configuration.md +145 -0
- package/template-starter/docs/guides/github-pages-deployment.md +254 -0
- package/template-starter/docs/guides/netlify-deployment.md +159 -0
- package/template-starter/docs/guides/vercel-deployment.md +131 -0
- package/template-starter/docs/index.md +49 -0
- package/template-starter/docs/setup.md +149 -0
- package/template-starter/package.json +31 -0
- package/template-starter/pagefind.toml +3 -0
- package/template-starter/postcss.config.js +5 -0
- package/template-starter/src/app.css +34 -0
- package/template-starter/src/app.d.ts +13 -0
- package/template-starter/src/app.html +11 -0
- package/template-starter/src/lib/components/APITable.svelte +120 -0
- package/template-starter/src/lib/components/APITable.test.ts +19 -0
- package/template-starter/src/lib/components/Breadcrumbs.svelte +85 -0
- package/template-starter/src/lib/components/Breadcrumbs.test.ts +19 -0
- package/template-starter/src/lib/components/Callout.svelte +60 -0
- package/template-starter/src/lib/components/Callout.test.ts +16 -0
- package/template-starter/src/lib/components/CodeBlock.svelte +68 -0
- package/template-starter/src/lib/components/CodeBlock.test.ts +12 -0
- package/template-starter/src/lib/components/DocLayout.svelte +84 -0
- package/template-starter/src/lib/components/Footer.svelte +78 -0
- package/template-starter/src/lib/components/Image.svelte +100 -0
- package/template-starter/src/lib/components/Image.test.ts +15 -0
- package/template-starter/src/lib/components/Navbar.svelte +141 -0
- package/template-starter/src/lib/components/Search.svelte +248 -0
- package/template-starter/src/lib/components/Sidebar.svelte +110 -0
- package/template-starter/src/lib/components/Tabs.svelte +48 -0
- package/template-starter/src/lib/components/Tabs.test.ts +17 -0
- package/template-starter/src/lib/index.ts +15 -0
- package/template-starter/src/routes/+layout.svelte +28 -0
- package/template-starter/src/routes/+page.svelte +92 -0
- package/template-starter/svelte.config.js +17 -0
- package/template-starter/tailwind.config.ts +17 -0
- package/template-starter/tsconfig.json +13 -0
- package/template-starter/vite.config.ts +6 -0
- package/tests/e2e/example.spec.ts +345 -0
- package/tsconfig.json +20 -0
- package/vite.config.ts +6 -0
- package/vitest.config.ts +34 -0
- package/vitest.setup.ts +21 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example E2E Tests
|
|
5
|
+
* Demonstrates the structure of E2E tests for Svelte Docs System
|
|
6
|
+
*
|
|
7
|
+
* Note: These tests require Playwright to be installed
|
|
8
|
+
* Run with: npm run test:e2e
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
test.describe('Documentation System E2E', () => {
|
|
12
|
+
test.beforeEach(async ({ page }) => {
|
|
13
|
+
// Navigate to the documentation homepage before each test
|
|
14
|
+
await page.goto('/');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test.describe('Navigation', () => {
|
|
18
|
+
test('should navigate between pages', async ({ page }) => {
|
|
19
|
+
// Find and click a navigation link
|
|
20
|
+
await page.click('a[href="/docs/guides"]');
|
|
21
|
+
|
|
22
|
+
// Wait for navigation and verify page content
|
|
23
|
+
await page.waitForURL('/docs/guides');
|
|
24
|
+
expect(page.url()).toContain('/docs/guides');
|
|
25
|
+
|
|
26
|
+
// Verify content loaded
|
|
27
|
+
const heading = await page.locator('h1');
|
|
28
|
+
await expect(heading).toBeVisible();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should display breadcrumbs', async ({ page }) => {
|
|
32
|
+
await page.goto('/docs/guides/getting-started');
|
|
33
|
+
|
|
34
|
+
// Check breadcrumb structure
|
|
35
|
+
const breadcrumbs = page.locator('[role="navigation"] a');
|
|
36
|
+
const count = await breadcrumbs.count();
|
|
37
|
+
|
|
38
|
+
expect(count).toBeGreaterThan(0);
|
|
39
|
+
|
|
40
|
+
// Verify breadcrumb content
|
|
41
|
+
const lastBreadcrumb = breadcrumbs.nth(count - 1);
|
|
42
|
+
await expect(lastBreadcrumb).toContainText(/Getting Started|getting-started/i);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should update active navigation item', async ({ page }) => {
|
|
46
|
+
const navItem = page.locator('nav a').first();
|
|
47
|
+
|
|
48
|
+
await navItem.click();
|
|
49
|
+
await page.waitForLoadState('networkidle');
|
|
50
|
+
|
|
51
|
+
// Check if active class is applied
|
|
52
|
+
const activeItem = page.locator('nav a.active, nav a[aria-current]').first();
|
|
53
|
+
await expect(activeItem).toBeVisible();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test.describe('Search', () => {
|
|
58
|
+
test('should search and display results', async ({ page }) => {
|
|
59
|
+
// Click search input
|
|
60
|
+
const searchInput = page.locator('input[placeholder*="Search"]');
|
|
61
|
+
await searchInput.click();
|
|
62
|
+
|
|
63
|
+
// Type search query
|
|
64
|
+
await searchInput.fill('getting started');
|
|
65
|
+
|
|
66
|
+
// Wait for results to appear
|
|
67
|
+
const searchResults = page.locator('[role="listbox"], .search-results');
|
|
68
|
+
await expect(searchResults).toBeVisible();
|
|
69
|
+
|
|
70
|
+
// Verify results contain the query
|
|
71
|
+
const resultItems = page.locator('[role="option"], .search-result-item');
|
|
72
|
+
expect(await resultItems.count()).toBeGreaterThan(0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('should navigate to search result', async ({ page }) => {
|
|
76
|
+
const searchInput = page.locator('input[placeholder*="Search"]');
|
|
77
|
+
await searchInput.fill('API');
|
|
78
|
+
|
|
79
|
+
// Wait for results and click first one
|
|
80
|
+
const firstResult = page.locator('[role="option"], .search-result-item').first();
|
|
81
|
+
await firstResult.click();
|
|
82
|
+
|
|
83
|
+
// Verify navigation happened
|
|
84
|
+
await page.waitForLoadState('networkidle');
|
|
85
|
+
expect(page.url()).toContain('/');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('should show no results message', async ({ page }) => {
|
|
89
|
+
const searchInput = page.locator('input[placeholder*="Search"]');
|
|
90
|
+
await searchInput.fill('xyzabc123notarealterm');
|
|
91
|
+
|
|
92
|
+
// Wait a bit for search to complete
|
|
93
|
+
await page.waitForTimeout(500);
|
|
94
|
+
|
|
95
|
+
// Check for no results message
|
|
96
|
+
const noResultsMsg = page.locator('text=/No results|nothing found/i');
|
|
97
|
+
await expect(noResultsMsg).toBeVisible();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test.describe('Dark Mode', () => {
|
|
102
|
+
test('should toggle dark mode', async ({ page }) => {
|
|
103
|
+
// Find and click dark mode toggle
|
|
104
|
+
const darkModeToggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
|
|
105
|
+
|
|
106
|
+
// Get initial state
|
|
107
|
+
const htmlElement = page.locator('html');
|
|
108
|
+
const initialClass = await htmlElement.getAttribute('class');
|
|
109
|
+
|
|
110
|
+
// Click toggle
|
|
111
|
+
await darkModeToggle.click();
|
|
112
|
+
|
|
113
|
+
// Verify class changed
|
|
114
|
+
const newClass = await htmlElement.getAttribute('class');
|
|
115
|
+
expect(newClass).not.toBe(initialClass);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should persist dark mode preference', async ({ page, context }) => {
|
|
119
|
+
// Enable dark mode
|
|
120
|
+
const toggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
|
|
121
|
+
await toggle.click();
|
|
122
|
+
|
|
123
|
+
// Verify it's enabled
|
|
124
|
+
const htmlElement = page.locator('html');
|
|
125
|
+
const isDarkMode = (await htmlElement.getAttribute('class'))?.includes('dark');
|
|
126
|
+
expect(isDarkMode).toBeTruthy();
|
|
127
|
+
|
|
128
|
+
// Reload page
|
|
129
|
+
await page.reload();
|
|
130
|
+
|
|
131
|
+
// Verify dark mode still active
|
|
132
|
+
const isDarkModeAfterReload = (
|
|
133
|
+
await htmlElement.getAttribute('class')
|
|
134
|
+
)?.includes('dark');
|
|
135
|
+
expect(isDarkModeAfterReload).toBeTruthy();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('should have readable text in dark mode', async ({ page }) => {
|
|
139
|
+
// Enable dark mode
|
|
140
|
+
const toggle = page.locator('[aria-label*="Dark"], [aria-label*="Theme"]');
|
|
141
|
+
await toggle.click();
|
|
142
|
+
|
|
143
|
+
// Get text color and background color
|
|
144
|
+
const mainContent = page.locator('main').first();
|
|
145
|
+
|
|
146
|
+
const styles = await mainContent.evaluate((el) => {
|
|
147
|
+
const computed = window.getComputedStyle(el);
|
|
148
|
+
return {
|
|
149
|
+
color: computed.color,
|
|
150
|
+
backgroundColor: computed.backgroundColor
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Verify colors are defined
|
|
155
|
+
expect(styles.color).toBeTruthy();
|
|
156
|
+
expect(styles.backgroundColor).toBeTruthy();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test.describe('Responsive Design', () => {
|
|
161
|
+
test('should show mobile menu on small screens', async ({ page }) => {
|
|
162
|
+
// Set mobile viewport
|
|
163
|
+
await page.setViewportSize({ width: 375, height: 667 });
|
|
164
|
+
|
|
165
|
+
// Look for hamburger menu
|
|
166
|
+
const hamburgerMenu = page.locator('[aria-label*="Menu"], [aria-label*="Navigation"]');
|
|
167
|
+
await expect(hamburgerMenu).toBeVisible();
|
|
168
|
+
|
|
169
|
+
// Click hamburger
|
|
170
|
+
await hamburgerMenu.click();
|
|
171
|
+
|
|
172
|
+
// Verify menu opens
|
|
173
|
+
const mobileNav = page.locator('nav').first();
|
|
174
|
+
await expect(mobileNav).toBeVisible();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('should show sidebar on desktop', async ({ page }) => {
|
|
178
|
+
// Set desktop viewport
|
|
179
|
+
await page.setViewportSize({ width: 1440, height: 900 });
|
|
180
|
+
|
|
181
|
+
// Sidebar should be visible
|
|
182
|
+
const sidebar = page.locator('aside, nav');
|
|
183
|
+
await expect(sidebar.first()).toBeVisible();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test.describe('Accessibility', () => {
|
|
188
|
+
test('should be keyboard navigable', async ({ page }) => {
|
|
189
|
+
// Tab through page elements
|
|
190
|
+
const firstButton = page.locator('button').first();
|
|
191
|
+
|
|
192
|
+
// Initially should not have focus
|
|
193
|
+
let hasFocus = await firstButton.evaluate((el) => el === document.activeElement);
|
|
194
|
+
expect(hasFocus).toBeFalsy();
|
|
195
|
+
|
|
196
|
+
// Press Tab and verify focus appears
|
|
197
|
+
await page.keyboard.press('Tab');
|
|
198
|
+
|
|
199
|
+
// Check if any element has focus
|
|
200
|
+
const focusedElement = await page.evaluate(() => {
|
|
201
|
+
return document.activeElement?.tagName;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
expect(focusedElement).toBeTruthy();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('should have alt text for images', async ({ page }) => {
|
|
208
|
+
const images = page.locator('img');
|
|
209
|
+
|
|
210
|
+
const count = await images.count();
|
|
211
|
+
if (count > 0) {
|
|
212
|
+
// Get alt text of first image
|
|
213
|
+
const altText = await images.first().getAttribute('alt');
|
|
214
|
+
|
|
215
|
+
// Should have alt text (if decorative, should be empty intentionally)
|
|
216
|
+
expect(altText).not.toBeNull();
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test('should have proper heading hierarchy', async ({ page }) => {
|
|
221
|
+
const h1Count = await page.locator('h1').count();
|
|
222
|
+
const h2s = await page.locator('h2').count();
|
|
223
|
+
|
|
224
|
+
// Page should have exactly one h1
|
|
225
|
+
expect(h1Count).toBe(1);
|
|
226
|
+
|
|
227
|
+
// h2s should exist (if multiple sections)
|
|
228
|
+
// This is flexible as some pages might not have subsections
|
|
229
|
+
expect(h2s).toBeGreaterThanOrEqual(0);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test.describe('Content Display', () => {
|
|
234
|
+
test('should render markdown content', async ({ page }) => {
|
|
235
|
+
// Navigate to a content page
|
|
236
|
+
await page.goto('/docs');
|
|
237
|
+
|
|
238
|
+
// Wait for main content to load
|
|
239
|
+
const mainContent = page.locator('main, article').first();
|
|
240
|
+
await expect(mainContent).toBeVisible();
|
|
241
|
+
|
|
242
|
+
// Verify content exists
|
|
243
|
+
const text = await mainContent.textContent();
|
|
244
|
+
expect(text).toBeTruthy();
|
|
245
|
+
expect(text?.length).toBeGreaterThan(0);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('should display code blocks with syntax highlighting', async ({ page }) => {
|
|
249
|
+
const codeBlocks = page.locator('pre, code');
|
|
250
|
+
|
|
251
|
+
if (await codeBlocks.count() > 0) {
|
|
252
|
+
const firstCode = codeBlocks.first();
|
|
253
|
+
await expect(firstCode).toBeVisible();
|
|
254
|
+
|
|
255
|
+
// Verify code content
|
|
256
|
+
const content = await firstCode.textContent();
|
|
257
|
+
expect(content).toBeTruthy();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test('should have functional copy button on code blocks', async ({ page }) => {
|
|
262
|
+
const codeBlock = page.locator('pre').first();
|
|
263
|
+
|
|
264
|
+
if (await codeBlock.isVisible()) {
|
|
265
|
+
const copyButton = page
|
|
266
|
+
.locator('button')
|
|
267
|
+
.filter({ hasText: /Copy|copy/ })
|
|
268
|
+
.first();
|
|
269
|
+
|
|
270
|
+
if (await copyButton.isVisible()) {
|
|
271
|
+
// Click copy button
|
|
272
|
+
await copyButton.click();
|
|
273
|
+
|
|
274
|
+
// Verify some feedback (success message, button state change, etc.)
|
|
275
|
+
const successMsg = page.locator('text=/copied|success/i').first();
|
|
276
|
+
await expect(successMsg).toBeVisible({ timeout: 2000 });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test.describe('Performance', () => {
|
|
283
|
+
test('should load page within acceptable time', async ({ page }) => {
|
|
284
|
+
const startTime = Date.now();
|
|
285
|
+
|
|
286
|
+
await page.goto('/');
|
|
287
|
+
await page.waitForLoadState('networkidle');
|
|
288
|
+
|
|
289
|
+
const loadTime = Date.now() - startTime;
|
|
290
|
+
|
|
291
|
+
// Page should load within 3 seconds
|
|
292
|
+
expect(loadTime).toBeLessThan(3000);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('should have good Core Web Vitals', async ({ page }) => {
|
|
296
|
+
await page.goto('/');
|
|
297
|
+
|
|
298
|
+
const vitals = await page.evaluate(() => {
|
|
299
|
+
return new Promise<any>((resolve) => {
|
|
300
|
+
let lcp = 0;
|
|
301
|
+
let cls = 0;
|
|
302
|
+
|
|
303
|
+
const observer = new PerformanceObserver((list) => {
|
|
304
|
+
for (const entry of list.getEntries()) {
|
|
305
|
+
if ((entry as any).name === 'largest-contentful-paint') {
|
|
306
|
+
lcp = (entry as any).renderTime || (entry as any).loadTime;
|
|
307
|
+
} else if ((entry as any).hadRecentInput === false) {
|
|
308
|
+
cls += (entry as any).value;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
observer.observe({ entryTypes: ['largest-contentful-paint', 'layout-shift'] });
|
|
314
|
+
|
|
315
|
+
setTimeout(() => {
|
|
316
|
+
observer.disconnect();
|
|
317
|
+
resolve({ lcp, cls });
|
|
318
|
+
}, 3000);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// LCP should be less than 2.5 seconds
|
|
323
|
+
expect(vitals.lcp).toBeLessThan(2500);
|
|
324
|
+
|
|
325
|
+
// CLS should be less than 0.1
|
|
326
|
+
expect(vitals.cls).toBeLessThan(0.1);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test.describe('Error Handling', () => {
|
|
332
|
+
test('should show 404 page for non-existent routes', async ({ page }) => {
|
|
333
|
+
await page.goto('/docs/this-page-does-not-exist-123');
|
|
334
|
+
|
|
335
|
+
// Should see 404 message or not found page
|
|
336
|
+
const notFoundMsg = page.locator('text=/404|not found|does not exist/i');
|
|
337
|
+
|
|
338
|
+
// Try to find error message
|
|
339
|
+
const hasError =
|
|
340
|
+
(await notFoundMsg.count()) > 0 ||
|
|
341
|
+
page.url().includes('404');
|
|
342
|
+
|
|
343
|
+
expect(hasError).toBeTruthy();
|
|
344
|
+
});
|
|
345
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./.svelte-kit/tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rewriteRelativeImportExtensions": true,
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"checkJs": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"moduleResolution": "bundler"
|
|
14
|
+
}
|
|
15
|
+
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
|
16
|
+
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
|
17
|
+
//
|
|
18
|
+
// To make changes to top-level options such as include and exclude, we recommend extending
|
|
19
|
+
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
|
20
|
+
}
|
package/vite.config.ts
ADDED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [sveltekit()],
|
|
6
|
+
test: {
|
|
7
|
+
globals: true,
|
|
8
|
+
environment: 'jsdom',
|
|
9
|
+
setupFiles: ['./vitest.setup.ts'],
|
|
10
|
+
// Ensure we use browser build of Svelte
|
|
11
|
+
alias: {
|
|
12
|
+
'svelte/internal': 'svelte/internal'
|
|
13
|
+
},
|
|
14
|
+
coverage: {
|
|
15
|
+
provider: 'v8',
|
|
16
|
+
reporter: ['text', 'json', 'html', 'lcov'],
|
|
17
|
+
exclude: [
|
|
18
|
+
'node_modules/',
|
|
19
|
+
'dist/',
|
|
20
|
+
'build/',
|
|
21
|
+
'coverage/',
|
|
22
|
+
'**/*.test.ts',
|
|
23
|
+
'**/*.spec.ts',
|
|
24
|
+
'tests/',
|
|
25
|
+
'template-starter/'
|
|
26
|
+
],
|
|
27
|
+
include: ['src/lib/**/*.ts', 'src/lib/**/*.svelte'],
|
|
28
|
+
lines: 85,
|
|
29
|
+
functions: 85,
|
|
30
|
+
branches: 80,
|
|
31
|
+
statements: 85
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
package/vitest.setup.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { expect, afterEach, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { cleanup } from '@testing-library/svelte';
|
|
3
|
+
|
|
4
|
+
// Cleanup after each test
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
cleanup();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// Initialize and clear storage if available
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
try {
|
|
12
|
+
if (typeof localStorage !== 'undefined' && localStorage.clear) {
|
|
13
|
+
localStorage.clear();
|
|
14
|
+
}
|
|
15
|
+
if (typeof sessionStorage !== 'undefined' && sessionStorage.clear) {
|
|
16
|
+
sessionStorage.clear();
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
// Storage might not be available in some test environments
|
|
20
|
+
}
|
|
21
|
+
});
|