Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add tests for build post list script #3284

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
7ae14bd
fefewg
vishvamsinh28 Oct 22, 2024
d1cb179
added logs for debugging
vishvamsinh28 Oct 22, 2024
e5d6aab
Merge branch 'master' into buildPostTest
anshgoyalevil Oct 26, 2024
cc57d88
Merge branch 'master' into buildPostTest
anshgoyalevil Oct 31, 2024
fbcd76b
lint fix
anshgoyalevil Oct 31, 2024
17dedfe
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 4, 2024
23a5c98
feqf
vishvamsinh28 Nov 4, 2024
ec110dc
feqfeq
vishvamsinh28 Nov 4, 2024
b653ecf
ffqef
vishvamsinh28 Nov 4, 2024
accec3e
path update
vishvamsinh28 Nov 4, 2024
bb4ffe0
path update
vishvamsinh28 Nov 4, 2024
c24eb8e
logs added
vishvamsinh28 Nov 4, 2024
63edd8d
fwf
vishvamsinh28 Nov 4, 2024
b87b00d
logs added
vishvamsinh28 Nov 4, 2024
0f15784
posix
vishvamsinh28 Nov 4, 2024
8f26f50
fwqfqw
vishvamsinh28 Nov 4, 2024
10453f4
path chanegs
vishvamsinh28 Nov 4, 2024
323cdc5
fqwefe
vishvamsinh28 Nov 5, 2024
bb2d6b6
used fs extra
vishvamsinh28 Nov 5, 2024
cf53980
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 8, 2024
abfea38
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 9, 2024
a9c95d9
path fix
vishvamsinh28 Nov 9, 2024
a3a8dca
qwfeg
vishvamsinh28 Nov 9, 2024
70a0cd1
remove logs
vishvamsinh28 Nov 9, 2024
1383ea6
apply coderabbit suggetions
vishvamsinh28 Nov 9, 2024
fd129fe
fge
vishvamsinh28 Nov 9, 2024
e63203f
update tests
vishvamsinh28 Nov 9, 2024
b7e8c77
tests updated
vishvamsinh28 Nov 9, 2024
4d7b5a0
fef
vishvamsinh28 Nov 9, 2024
fa51639
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 10, 2024
09b530d
updated details.slug
vishvamsinh28 Nov 10, 2024
69ca91a
quick fix
vishvamsinh28 Nov 10, 2024
b935133
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 11, 2024
0c420ef
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 13, 2024
4615938
nkn
vishvamsinh28 Nov 13, 2024
281a8c8
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 15, 2024
5ba7c2d
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 22, 2024
a1e6a45
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 23, 2024
f7cf1b6
applied suggested changes
vishvamsinh28 Nov 23, 2024
a0fe58d
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 28, 2024
dc0998f
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 29, 2024
5357992
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 29, 2024
3c6618d
Merge branch 'master' into buildPostTest
vishvamsinh28 Nov 30, 2024
cf9920e
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 2, 2024
e2868d9
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 4, 2024
49722d0
apply nitpick
vishvamsinh28 Dec 4, 2024
ba08b4c
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 5, 2024
e0ac1e1
Merge branch 'master' into buildPostTest
akshatnema Dec 7, 2024
dc7e215
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 8, 2024
f8e7dfd
format code
vishvamsinh28 Dec 8, 2024
bb4da1d
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 9, 2024
45adee8
added helper function for setup
vishvamsinh28 Dec 9, 2024
d175e5c
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 9, 2024
98231ea
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 10, 2024
4893712
apply coderabbit suggestions
vishvamsinh28 Dec 10, 2024
10d1b72
apply coderabbit suggestion
vishvamsinh28 Dec 10, 2024
4a38f98
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 12, 2024
80b04b1
Merge branch 'master' into buildPostTest
vishvamsinh28 Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions scripts/build-post-list.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { readdirSync, statSync, existsSync, readFileSync, writeFileSync } = require('fs')
const { resolve, basename } = require('path')
const { basename } = require('path')
const frontMatter = require('gray-matter')
const toc = require('markdown-toc')
const { slugify } = require('markdown-toc/lib/utils')
Expand All @@ -15,36 +15,36 @@ const result = {
docsTree: {}
}
const releaseNotes = []
const basePath = 'pages'
const postDirectories = [
// order of these directories is important, as the blog should come before docs, to create a list of available release notes, which will later be used to release-note-link for spec docs
[`${basePath}/blog`, '/blog'],
[`${basePath}/docs`, '/docs'],
[`${basePath}/about`, '/about']
];

const addItem = (details) => {
if(details.slug.startsWith('/docs'))
if (details.slug.startsWith('/docs'))
result["docs"].push(details)
else if(details.slug.startsWith('/blog'))
else if (details.slug.startsWith('/blog'))
result["blog"].push(details)
else if(details.slug.startsWith('/about'))
else if (details.slug.startsWith('/about'))
result["about"].push(details)
else {}
else { }
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

module.exports = async function buildPostList() {
walkDirectories(postDirectories, result)
const treePosts = buildNavTree(result["docs"].filter((p) => p.slug.startsWith('/docs/')))
result["docsTree"] = treePosts
result["docs"] = addDocButtons(result["docs"], treePosts)
if (process.env.NODE_ENV === 'production') {
// console.log(inspect(result, { depth: null, colors: true }))
async function buildPostList(postDirectories, basePath, writeFilePath) {
try {
if (postDirectories.length === 0) {
throw new Error('Error while building post list: No post directories provided');
}
walkDirectories(postDirectories, result, basePath)
const treePosts = buildNavTree(result["docs"].filter((p) => p.slug.startsWith('/docs/')))
result["docsTree"] = treePosts
result["docs"] = addDocButtons(result["docs"], treePosts)
if (process.env.NODE_ENV === 'production') {
// console.log(inspect(result, { depth: null, colors: true }))
}
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
writeFileSync(writeFilePath, JSON.stringify(result, null, ' '))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this part if this block is doing nothing. It will increase your branch converage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed it

coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
throw new Error(`Error while building post list: ${error.message}`);
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
}
writeFileSync(resolve(__dirname, '..', 'config', 'posts.json'), JSON.stringify(result, null, ' '))
}

function walkDirectories(directories, result, sectionWeight = 0, sectionTitle, sectionId, rootSectionId) {
function walkDirectories(directories, result, basePath, sectionWeight = 0, sectionTitle, sectionId, rootSectionId) {
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
for (let dir of directories) {
let directory = dir[0]
let sectionSlug = dir[1] || ''
Expand All @@ -68,8 +68,8 @@ function walkDirectories(directories, result, sectionWeight = 0, sectionTitle, s
}
details.isSection = true
if (slugElements.length > 3) {
details.parent = slugElements[slugElements.length - 2]
details.sectionId = slugElements[slugElements.length - 1]
details.parent = slugElements[slugElements.length - 2]
details.sectionId = slugElements[slugElements.length - 1]
}
if (!details.parent) {
details.isRootSection = true
Expand All @@ -79,7 +79,7 @@ function walkDirectories(directories, result, sectionWeight = 0, sectionTitle, s
details.slug = slug
addItem(details)
const rootId = details.parent || details.rootSectionId
walkDirectories([[fileName, slug]], result, details.weight, details.title, details.sectionId, rootId)
walkDirectories([[fileName, slug]], result, basePath, details.weight, details.title, details.sectionId, rootId)
} else if (file.endsWith('.mdx') && !fileName.endsWith('/_section.mdx')) {
const fileContent = readFileSync(fileName, 'utf-8')
// Passing a second argument to frontMatter disables cache. See https://github.com/asyncapi/website/issues/1057
Expand All @@ -96,18 +96,18 @@ function walkDirectories(directories, result, sectionWeight = 0, sectionTitle, s
details.id = fileName
details.isIndex = fileName.endsWith('/index.mdx')
details.slug = details.isIndex ? sectionSlug : slug.replace(/\.mdx$/, '')
if(details.slug.includes('/reference/specification/') && !details.title) {
if (details.slug.includes('/reference/specification/') && !details.title) {
const fileBaseName = basename(data.slug) // ex. v2.0.0 | v2.1.0-next-spec.1
Copy link

@coderabbitai coderabbitai bot Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct variable usage for consistency

The variable data.slug may not be defined at this point. Since details.slug has been set, use it instead to avoid potential undefined errors.

Apply this diff to use the correct variable:

-            const fileBaseName = basename(data.slug)  // ex. v2.0.0 | v2.1.0-next-spec.1
+            const fileBaseName = basename(details.slug)  // ex. v2.0.0 | v2.1.0-next-spec.1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fileBaseName = basename(data.slug) // ex. v2.0.0 | v2.1.0-next-spec.1
const fileBaseName = basename(details.slug) // ex. v2.0.0 | v2.1.0-next-spec.1
🧰 Tools
🪛 eslint

[error] 104-104: Replace · with ;

(prettier/prettier)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vishvamsinh28 Is this correct?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. replaced it with (data.slug || details.slug)

This way, it defaults to details.slug if data.slug is missing, avoiding any errors.

const fileName = fileBaseName.split('-')[0] // v2.0.0 | v2.1.0
details.weight = specWeight--

if (fileName.startsWith('v')) {
details.title = capitalize(fileName.slice(1))
details.title = capitalize(fileName.slice(1))
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
} else {
details.title = capitalize(fileName)
}

if(releaseNotes.includes(details.title)){
if (releaseNotes.includes(details.title)) {
details.releaseNoteLink = `/blog/release-notes-${details.title}`
}

Expand All @@ -122,10 +122,10 @@ function walkDirectories(directories, result, sectionWeight = 0, sectionTitle, s
}

// To create a list of available ReleaseNotes list, which will be used to add details.releaseNoteLink attribute.
if(file.startsWith("release-notes") && dir[1] === "/blog"){
const fileName_without_extension = file.slice(0,-4)
if (file.startsWith("release-notes") && dir[1] === "/blog") {
const fileName_without_extension = file.slice(0, -4)
// removes the file extension. For example, release-notes-2.1.0.md -> release-notes-2.1.0
const version = fileName_without_extension.slice(fileName_without_extension.lastIndexOf("-")+1)
const version = fileName_without_extension.slice(fileName_without_extension.lastIndexOf("-") + 1)
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved

// gets the version from the name of the releaseNote .md file (from /blog). For example, version = 2.1.0 if fileName_without_extension = release-notes-2.1.0
releaseNotes.push(version)
Expand Down Expand Up @@ -159,3 +159,5 @@ function isDirectory(dir) {
function capitalize(text) {
return text.split(/[\s\-]/g).map(word => `${word[0].toUpperCase()}${word.substr(1)}`).join(' ')
}

module.exports = {slugifyToC, buildPostList}
14 changes: 12 additions & 2 deletions scripts/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
const { resolve } = require('path');
const fs = require('fs');
const rssFeed = require('./build-rss');
const buildPostList = require('./build-post-list');
const {buildPostList} = require('./build-post-list');
const buildCaseStudiesList = require('./casestudies');
const buildAdoptersList = require('./adopters');
const buildFinanceInfoList = require('./finance');

async function start() {
await buildPostList();

const postDirectories = [
['pages/blog', '/blog'],
['pages/docs', '/docs'],
['pages/about', '/about']
];
const basePath = 'pages';
const writeFilePath = resolve(__dirname, '../config', 'posts.json');

await buildPostList(postDirectories, basePath, writeFilePath);

rssFeed(
'blog',
'AsyncAPI Initiative Blog RSS Feed',
Expand Down
192 changes: 192 additions & 0 deletions tests/build-post-list.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
const { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } = require('fs');
const { resolve, join } = require('path');
const { buildPostList, slugifyToC } = require('../scripts/build-post-list');

describe('buildPostList', () => {
let tempDir;
let writeFilePath;
let postDirectories;

beforeEach(() => {
tempDir = resolve(__dirname, `test-config`);
writeFilePath = resolve(tempDir, 'posts.json');
postDirectories = [
[join(tempDir, 'blog'), '/blog'],
[join(tempDir, 'docs'), '/docs'],
[join(tempDir, 'about'), '/about'],
];

mkdirSync(tempDir, { recursive: true });

mkdirSync(join(tempDir, 'blog'), { recursive: true });
writeFileSync(join(tempDir, 'blog', 'release-notes-2.1.0.mdx'), '---\ntitle: Release Notes 2.1.0\n---\nThis is a release note.');

mkdirSync(join(tempDir, 'docs'), { recursive: true });
writeFileSync(join(tempDir, 'docs', 'index.mdx'), '---\ntitle: Docs Home\n---\nThis is the documentation homepage.');

mkdirSync(join(tempDir, 'about'), { recursive: true });
writeFileSync(join(tempDir, 'about', 'index.mdx'), '---\ntitle: About Us\n---\nThis is the about page.');

mkdirSync(join(tempDir, 'docs', 'reference', 'specification'), { recursive: true });
});

afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});

it('builds a post list and writes the result to a file', async () => {

await buildPostList(postDirectories, tempDir, writeFilePath);

const outputExists = existsSync(writeFilePath);
expect(outputExists).toBe(true);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));

expect(output).toHaveProperty('docs');
expect(output).toHaveProperty('blog');
expect(output).toHaveProperty('about');
expect(output).toHaveProperty('docsTree');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(output).toHaveProperty('docs');
expect(output).toHaveProperty('blog');
expect(output).toHaveProperty('about');
expect(output).toHaveProperty('docsTree');
expect(output).toMatchObject({
docs: expect.arrayContaining([
expect.objectContaining({
title: 'Docs Home',
slug: '/docs/index'
})
]),
blog: expect.arrayContaining([
expect.objectContaining({
title: 'Release Notes 2.1.0',
slug: '/blog/release-notes-2.1.0'
})
]),
about: expect.arrayContaining([
expect.objectContaining({
title: 'About Us',
slug: '/about/index'
})
]),
docsTree: expect.any(Object)
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


const blogEntry = output.blog.find(item => item.slug === '/blog/release-notes-2.1.0');
expect(blogEntry).toBeDefined();
expect(blogEntry.title).toBe('Release Notes 2.1.0');
});

it('handles a directory with only section files', async () => {
mkdirSync(join(tempDir, 'docs', 'section1'), { recursive: true });
writeFileSync(join(tempDir, 'docs', 'section1', '_section.mdx'), '---\ntitle: Section 1\n---\nThis is section 1.');

await buildPostList(postDirectories, tempDir, writeFilePath);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));

expect(output.docs.length).toBeGreaterThan(0);
expect(output.docs.find(item => item.title === 'Section 1')).toBeDefined();
Copy link
Member

@akshatnema akshatnema Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(output.docs.length).toBeGreaterThan(0);
expect(output.docs.find(item => item.title === 'Section 1')).toBeDefined();
const sectionEntry = output.docs.find(item => item.title === 'Section 1');
expect(sectionEntry).toMatchObject({
title: 'Section 1',
slug: expect.stringContaining('/docs/section1'),
isSection: true
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

});

it('handles multiple release notes correctly', async () => {
writeFileSync(join(tempDir, 'blog', 'release-notes-2.1.1.mdx'), '---\ntitle: Release Notes 2.1.1\n---\nThis is a release note.');

await buildPostList(postDirectories, tempDir, writeFilePath);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));

const firstReleaseNote = output.blog.find(item => item.slug === '/blog/release-notes-2.1.0');
const secondReleaseNote = output.blog.find(item => item.slug === '/blog/release-notes-2.1.1');

expect(firstReleaseNote).toBeDefined();
expect(firstReleaseNote.title).toBe('Release Notes 2.1.0');

expect(secondReleaseNote).toBeDefined();
expect(secondReleaseNote.title).toBe('Release Notes 2.1.1');
});

it('handles errors gracefully', async () => {
const invalidDir = [join(tempDir, 'non-existent-dir'), '/invalid'];
await expect(buildPostList([invalidDir], tempDir, writeFilePath)).rejects.toThrow();
});

it('handles heading ids like {# myHeadingId}', () => {
const input = '## My Heading {#custom-id}';
expect(slugifyToC(input)).toBe('custom-id');
});

it('handles heading ids like {<a name="myHeadingId"/>}', () => {
const input = '## My Heading {<a name="custom-anchor-id"/>}';
expect(slugifyToC(input)).toBe('custom-anchor-id');
});

it('handles empty strings', () => {
expect(slugifyToC('')).toBe('');
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are not part of buildPostList. You can define different test suites inside same file, with different names under describe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
it('does not process specification files without a title', async () => {
const specDir = join(tempDir, 'docs', 'reference', 'specification');
writeFileSync(
join(specDir, 'v2.1.0-no-title.mdx'),
'---\n---\nContent of specification without a title.'
);

await buildPostList(postDirectories, tempDir, writeFilePath);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));
const noTitleEntry = output.docs.find(item => item.slug.includes('/reference/specification/v2.1.0-no-title'));

expect(noTitleEntry).toBeUndefined();
});

it('does not process specification files with "next-spec" in the filename', async () => {
const specDir = join(tempDir, 'docs', 'reference', 'specification');
writeFileSync(
join(specDir, 'v2.1.0-next-spec.1.mdx'),
'---\n---\nContent of pre-release specification v2.1.0-next-spec.1.'
);

await buildPostList(postDirectories, tempDir, writeFilePath);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));
const nextSpecEntry = output.docs.find(item => item.slug.includes('/reference/specification/v2.1.0-next-spec.1'));

expect(nextSpecEntry).toBeUndefined();
});

it('does not process specification files with "explorer" in the filename', async () => {
const specDir = join(tempDir, 'docs', 'reference', 'specification');
writeFileSync(
join(specDir, 'explorer.mdx'),
'---\n---\nContent of explorer specification.'
);

await buildPostList(postDirectories, tempDir, writeFilePath);

const output = JSON.parse(readFileSync(writeFilePath, 'utf-8'));
const explorerEntry = output.docs.find(item => item.slug.includes('/reference/specification/explorer'));

expect(explorerEntry).toBeUndefined();
});

it('throws an error if the directory cannot be read', async () => {
const invalidDir = [join(tempDir, 'non-existent-dir'), '/invalid'];

let error;
try {
await buildPostList([invalidDir], tempDir, writeFilePath);
} catch (err) {
error = err;
}

expect(error).toBeDefined();
expect(error.message).toMatch(/Error while building post list/);
});
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved


it('throws an error if the front matter cannot be parsed', async () => {
writeFileSync(join(tempDir, 'docs', 'invalid.mdx'), '---\ninvalid front matter\n---\nContent');

let error;
try {
await buildPostList(postDirectories, tempDir, writeFilePath);
} catch (err) {
error = err;
}

expect(error).toBeDefined();
expect(error.message).toMatch(/Error while building post list/);
});

it('throws an error if no post directories are provided', async () => {

let error;

try {
await buildPostList([], tempDir, writeFilePath);
} catch (err) {
error = err;
}

expect(error).toBeDefined();
expect(error.message).toMatch(/Error while building post list/);
});

});
2 changes: 1 addition & 1 deletion tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const rssFeed = require('../scripts/build-rss');
const buildPostList = require('../scripts/build-post-list');
const {buildPostList} = require('../scripts/build-post-list');
const buildCaseStudiesList = require('../scripts/casestudies');
const buildAdoptersList = require('../scripts/adopters');
const buildFinanceInfoList = require('../scripts/finance');
Expand Down
Loading