@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
JavaScript
;
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