UNPKG

@mdfriday/foundry

Version:

The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.

328 lines 18.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const index_1 = require("../index"); describe('Integration Tests - Business Scenarios', () => { describe('Hugo Content Management Scenarios', () => { describe('Blog Management', () => { test('should handle typical blog structure', () => { // Blog section index const blogIndex = index_1.PathDomain.createContentPath('/blog/_index.md'); expect(blogIndex.isBranchBundle()).toBe(true); expect(blogIndex.section()).toBe('blog'); expect(blogIndex.base()).toBe('/blog'); // Individual blog post const blogPost = index_1.PathDomain.createContentPath('/blog/my-first-post.md'); expect(blogPost.bundleType()).toBe(index_1.PathType.ContentSingle); expect(blogPost.section()).toBe('blog'); expect(blogPost.base()).toBe('/blog/my-first-post'); // Blog post with page bundle const blogBundle = index_1.PathDomain.createContentPath('/blog/my-post-bundle/index.md'); expect(blogBundle.isLeafBundle()).toBe(true); expect(blogBundle.container()).toBe('my-post-bundle'); expect(blogBundle.base()).toBe('/blog/my-post-bundle'); }); test('should handle blog with year/month organization', () => { const yearlyPost = index_1.PathDomain.createContentPath('/blog/2023/my-post.md'); const monthlyPost = index_1.PathDomain.createContentPath('/blog/2023/12/christmas-post.md'); const monthlyBundle = index_1.PathDomain.createContentPath('/blog/2023/12/special-post/index.md'); expect(yearlyPost.section()).toBe('blog'); expect(monthlyPost.section()).toBe('blog'); expect(monthlyBundle.section()).toBe('blog'); expect(monthlyBundle.isLeafBundle()).toBe(true); }); }); describe('Multi-language Site', () => { test('should handle multilingual content', () => { // English content const enIndex = index_1.PathDomain.createContentPath('/blog/_index.en.md'); const enPost = index_1.PathDomain.createContentPath('/blog/hello-world.en.md'); // French content const frIndex = index_1.PathDomain.createContentPath('/blog/_index.fr.md'); const frPost = index_1.PathDomain.createContentPath('/blog/hello-world.fr.md'); // Chinese content const zhPost = index_1.PathDomain.createContentPath('/blog/hello-world.zh.md'); expect(enIndex.lang()).toBe('.en'); expect(enPost.lang()).toBe('.en'); expect(frIndex.lang()).toBe('.fr'); expect(frPost.lang()).toBe('.fr'); expect(zhPost.lang()).toBe('.zh'); // Base names should be the same for translations expect(enPost.nameNoLang()).toBe('hello-world.md'); expect(frPost.nameNoLang()).toBe('hello-world.md'); expect(zhPost.nameNoLang()).toBe('hello-world.md'); }); test('should handle multilingual bundles', () => { const enBundle = index_1.PathDomain.createContentPath('/blog/my-post/index.en.md'); const frBundle = index_1.PathDomain.createContentPath('/blog/my-post/index.fr.md'); expect(enBundle.isLeafBundle()).toBe(true); expect(frBundle.isLeafBundle()).toBe(true); expect(enBundle.container()).toBe('my-post'); expect(frBundle.container()).toBe('my-post'); expect(enBundle.lang()).toBe('.en'); expect(frBundle.lang()).toBe('.fr'); }); }); describe('Documentation Site', () => { test('should handle nested documentation structure', () => { const docsIndex = index_1.PathDomain.createContentPath('/docs/_index.md'); const gettingStarted = index_1.PathDomain.createContentPath('/docs/getting-started.md'); const apiRef = index_1.PathDomain.createContentPath('/docs/api/reference.md'); const tutorialBundle = index_1.PathDomain.createContentPath('/docs/tutorials/basic/index.md'); expect(docsIndex.isBranchBundle()).toBe(true); expect(docsIndex.section()).toBe('docs'); expect(gettingStarted.bundleType()).toBe(index_1.PathType.ContentSingle); expect(gettingStarted.section()).toBe('docs'); expect(apiRef.section()).toBe('docs'); expect(apiRef.container()).toBe('api'); expect(tutorialBundle.isLeafBundle()).toBe(true); expect(tutorialBundle.section()).toBe('docs'); expect(tutorialBundle.container()).toBe('basic'); }); }); describe('E-commerce Site', () => { test('should handle product catalog structure', () => { const productsIndex = index_1.PathDomain.createContentPath('/products/_index.md'); const categoryIndex = index_1.PathDomain.createContentPath('/products/electronics/_index.md'); const productPage = index_1.PathDomain.createContentPath('/products/electronics/smartphone.md'); const productBundle = index_1.PathDomain.createContentPath('/products/electronics/laptop-bundle/index.md'); expect(productsIndex.isBranchBundle()).toBe(true); expect(categoryIndex.isBranchBundle()).toBe(true); expect(productPage.bundleType()).toBe(index_1.PathType.ContentSingle); expect(productBundle.isLeafBundle()).toBe(true); expect(productsIndex.section()).toBe('products'); expect(categoryIndex.section()).toBe('products'); expect(productPage.section()).toBe('products'); expect(productBundle.section()).toBe('products'); }); }); }); describe('Asset Management Scenarios', () => { test('should handle static assets', () => { const logo = index_1.PathDomain.createStaticPath('/images/logo.png'); const stylesheet = index_1.PathDomain.createStaticPath('/css/main.css'); const script = index_1.PathDomain.createStaticPath('/js/app.js'); expect(logo.isContent()).toBe(false); expect(stylesheet.isContent()).toBe(false); expect(script.isContent()).toBe(false); expect(logo.ext()).toBe('.png'); expect(stylesheet.ext()).toBe('.css'); expect(script.ext()).toBe('.js'); }); test('should handle theme assets', () => { const themeLayout = index_1.PathDomain.createThemePath('/mytheme/layouts/_default/single.html'); const themeAsset = index_1.PathDomain.createThemePath('/mytheme/static/css/theme.css'); expect(themeLayout.component()).toBe('themes'); expect(themeAsset.component()).toBe('themes'); }); }); describe('Content Relationships', () => { test('should determine parent-child relationships', () => { const sectionIndex = index_1.PathDomain.createContentPath('/blog/_index.md'); const blogPost = index_1.PathDomain.createContentPath('/blog/my-post.md'); const yearIndex = index_1.PathDomain.createContentPath('/blog/2023/_index.md'); const yearlyPost = index_1.PathDomain.createContentPath('/blog/2023/new-year.md'); // Check if posts are under their sections expect(index_1.PathDomain.isUnder(blogPost, sectionIndex)).toBe(true); expect(index_1.PathDomain.isUnder(yearlyPost, sectionIndex)).toBe(true); expect(index_1.PathDomain.isUnder(yearlyPost, yearIndex)).toBe(true); // Check relative paths const relativeToSection = index_1.PathDomain.relativeTo(sectionIndex, blogPost); expect(relativeToSection).toBeDefined(); }); test('should handle bundle resource relationships', () => { const leafBundle = index_1.PathDomain.createContentPath('/blog/my-post/index.md'); const bundleResource = index_1.PathDomain.createContentPath('/blog/my-post/image.jpg'); expect(leafBundle.isLeafBundle()).toBe(true); expect(bundleResource.isContent()).toBe(false); expect(leafBundle.container()).toBe(bundleResource.container()); }); }); describe('Path Normalization in Practice', () => { test('should handle user-generated content paths', () => { const messyPath = index_1.PathDomain.builder() .withComponent('content') .withPath('/Blog/My Awesome Post With CAPS and Spaces.md') .withNormalization(true) .withSpaceReplacement(true) .build(); expect(messyPath.path()).toBe('/blog/my-awesome-post-with-caps-and-spaces.md'); expect(messyPath.isContent()).toBe(true); // Preserve original for display purposes const original = messyPath.unnormalized(); expect(original.path()).toBe('/Blog/My Awesome Post With CAPS and Spaces.md'); }); test('should handle international content', () => { const internationalPaths = [ '/blog/文章标题.md', '/blog/статья-на-русском.md', '/blog/artículo-en-español.md', '/blog/記事のタイトル.md' ]; internationalPaths.forEach(path => { const contentPath = index_1.PathDomain.createContentPath(path); expect(contentPath.isContent()).toBe(true); expect(contentPath.section()).toBe('blog'); }); }); }); describe('Performance in Real-world Scenarios', () => { test('should handle large site with many pages', () => { const start = performance.now(); const paths = []; // Simulate a large blog site for (let year = 2020; year <= 2024; year++) { for (let month = 1; month <= 12; month++) { // Monthly index paths.push(index_1.PathDomain.createContentPath(`/blog/${year}/${month}/_index.md`)); // Posts for each month for (let post = 1; post <= 5; post++) { paths.push(index_1.PathDomain.createContentPath(`/blog/${year}/${month}/post-${post}.md`)); paths.push(index_1.PathDomain.createContentPath(`/blog/${year}/${month}/post-${post}.en.md`)); paths.push(index_1.PathDomain.createContentPath(`/blog/${year}/${month}/post-${post}.fr.md`)); } } } const end = performance.now(); expect(paths.length).toBe(5 * 12 * (1 + 3 * 5)); // years * months * (1 index + 3 * 5 posts) expect(end - start).toBeLessThan(2000); // Should complete within 2 seconds // Verify some random paths const randomPath = paths[Math.floor(Math.random() * paths.length)]; expect(randomPath.section()).toBe('blog'); expect(randomPath.isContent()).toBe(true); }); test('should efficiently sort and filter large path collections', () => { const paths = []; // Create mixed content types for (let i = 0; i < 1000; i++) { const pathType = i % 4; switch (pathType) { case 0: paths.push(index_1.PathDomain.createContentPath(`/blog/post-${i}.md`)); break; case 1: paths.push(index_1.PathDomain.createContentPath(`/docs/doc-${i}.md`)); break; case 2: paths.push(index_1.PathDomain.createContentPath(`/products/product-${i}/index.md`)); break; case 3: paths.push(index_1.PathDomain.createStaticPath(`/images/image-${i}.jpg`)); break; } } paths.push(index_1.PathDomain.createContentPath(`/products/_index.md`)); const start = performance.now(); // Filter operations const contentPaths = paths.filter(p => p.isContent()); const bundles = paths.filter(p => p.isBundle()); const blogPosts = paths.filter(p => p.section() === 'blog'); // Sort operations const sortedPaths = [...paths].sort(index_1.PathDomain.compare); const end = performance.now(); expect(contentPaths.length).toBeGreaterThan(0); expect(bundles.length).toBeGreaterThan(0); expect(blogPosts.length).toBeGreaterThan(0); expect(sortedPaths.length).toBe(paths.length); expect(end - start).toBeLessThan(500); // Should complete within 0.5 seconds }); }); describe('Error Handling in Production', () => { test('should gracefully handle malformed paths', () => { const malformedPaths = [ '//double//slash//path.md', '/path/with/../../../traversal.md', '/path/with/./current/./dir.md', '/path/ending/with/slash/', 'relative/path/without/leading/slash.md', '/path with spaces and special chars!@#$.md' ]; malformedPaths.forEach(path => { expect(() => { const parsed = index_1.PathDomain.createContentPath(path); expect(parsed).toBeDefined(); expect(parsed.path()).toBeDefined(); }).not.toThrow(); }); }); test('should handle edge cases in bundle detection', () => { const edgeCases = [ '/index.md', // Root index '/section/index.md', // Section leaf bundle '/section/_index.md', // Section branch bundle '/deeply/nested/structure/with/many/levels/index.md', '/section/subsection/_index.md', '/_index.md' // Site root branch bundle ]; edgeCases.forEach(path => { const parsed = index_1.PathDomain.createContentPath(path); expect(parsed.isBundle()).toBeDefined(); expect(typeof parsed.isBundle()).toBe('boolean'); if (parsed.isBundle()) { expect(parsed.bundleType()).toBeGreaterThanOrEqual(index_1.PathType.Leaf); } }); }); }); describe('Real-world Integration Examples', () => { test('should support content management workflow', () => { // 1. Create a new blog post draft const draftPost = index_1.PathDomain.builder() .withComponent('content') .withPath('/blog/drafts/My New Post.md') .withNormalization(true) .build(); expect(draftPost.path()).toBe('/blog/drafts/my-new-post.md'); expect(draftPost.section()).toBe('blog'); // 2. Convert to published post const publishedPost = index_1.PathDomain.createContentPath('/blog/2024/my-new-post.md'); expect(publishedPost.section()).toBe('blog'); expect(publishedPost.nameNoIdentifier()).toBe('my-new-post'); // 3. Create multilingual versions const enPost = index_1.PathDomain.createContentPath('/blog/2024/my-new-post.en.md'); const frPost = index_1.PathDomain.createContentPath('/blog/2024/my-new-post.fr.md'); expect(enPost.nameNoLang()).toBe('my-new-post.md'); expect(frPost.nameNoLang()).toBe('my-new-post.md'); }); test('should support theme development workflow', () => { // Layout templates const baseLayout = index_1.PathDomain.createLayoutPath('/_default/baseof.html'); const listLayout = index_1.PathDomain.createLayoutPath('/_default/list.html'); const singleLayout = index_1.PathDomain.createLayoutPath('/_default/single.html'); // Partial templates const headerPartial = index_1.PathDomain.createLayoutPath('/partials/header.html'); const footerPartial = index_1.PathDomain.createLayoutPath('/partials/footer.html'); // Shortcodes const shortcode = index_1.PathDomain.createLayoutPath('/shortcodes/youtube.html'); [baseLayout, listLayout, singleLayout, headerPartial, footerPartial, shortcode] .forEach(layout => { expect(layout.component()).toBe('layouts'); expect(layout.ext()).toBe('.html'); }); }); test('should support static site optimization', () => { // Identify all content pages for sitemap generation const allPages = [ index_1.PathDomain.createContentPath('/'), index_1.PathDomain.createContentPath('/about.md'), index_1.PathDomain.createContentPath('/blog/_index.md'), index_1.PathDomain.createContentPath('/blog/post1.md'), index_1.PathDomain.createContentPath('/blog/post2.md'), index_1.PathDomain.createContentPath('/docs/_index.md'), index_1.PathDomain.createContentPath('/docs/guide.md') ]; const contentPages = allPages.filter(p => p.isContent()); const sectionPages = allPages.filter(p => p.isBranchBundle()); expect(contentPages.length).toBeGreaterThan(0); expect(sectionPages.length).toBeGreaterThan(0); // Generate URL structure const urls = contentPages.map(p => ({ path: p.path(), section: p.section(), isIndex: p.isBundle(), lastmod: new Date().toISOString() })); expect(urls.length).toBe(contentPages.length); }); }); }); //# sourceMappingURL=integration.test.js.map