-
-
Notifications
You must be signed in to change notification settings - Fork 602
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: added test for build-rss.js #3101
base: master
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for asyncapi-website ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site configuration. |
⚡️ Lighthouse report for the changes in this PR:
Lighthouse ran on https://deploy-preview-3101--asyncapi-website.netlify.app/ |
@vishvamsinh28 Statement and branch coverage aren't 100% for this file. |
@anshgoyalevil updated the test, now it has 98.33% coverage. I will push another change to make it 100% |
scripts/build-rss.js
Outdated
const xml = json2xml.getXml(feed, '@', '', 2) | ||
fs.writeFileSync(`./public/${outputPath}`, xml, 'utf8') | ||
} catch (err) { | ||
throw new Error(`Failed to generate RSS feed: ${err.message}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of throwing error, can we return error as promise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are processing the script synchronously, so returning a promise wouldn't be appropriate here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching of error doesn't depend on whether the function is synchronous or asynchronous. It will still return the error, based on the function return type.
tests/build-rss.test.js
Outdated
}); | ||
|
||
it('should generate RSS feed and write to file', () => { | ||
rssFeed(type, title, desc, outputPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add a try/catch
block here to track the err variable here and see if any error is not returned from function execution? Try to do it for each test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
tests/fixtures/rssData.js
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we not following eslint rules inside this file? I see lot of indentation spaces here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not getting any lint errors locally, and I have removed unnecessary indentation in previous commits.
There's still room for improvement, @vishvamsinh28 |
tests/build-rss.test.js
Outdated
try { | ||
rssFeed(type, title, desc, outputPath); | ||
} catch (err) { | ||
console.error('Error encountered during test execution:', err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using console.error
, store the err
object inside a variable and during assertions, check that error object should be empty. This leads to the right approach to test the functions if they are executed perfectly or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, add the scenarios where the function should actually lead to an error, instead of executing it perfectly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vishvamsinh28 @anshgoyalevil Comment not addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add more tests for it. 👍 I can add a test to check if the user doesn't have a posts.json file, but for that, I'll have to temporarily rename the file. Should I add that test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, consider a scenario if data inside posts.json is in wrong manner. Then it should return error, right? Make the tests for those cases as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akshatnema updated the test
@akshatnema @anshgoyalevil Updated the test |
tests/build-rss.test.js
Outdated
jest.doMock('../config/posts.json', () => { | ||
throw new Error('Cannot find module'); | ||
}, { virtual: true }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you throwing an error here. The build-rss.js
file will do that.
Create the error situation for the file that needs to be tested, and let it throw the error.
@anshgoyalevil Any review for this PR ? |
WalkthroughThe changes introduce significant enhancements to the Changes
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🧹 Outside diff range and nitpick comments (7)
tests/fixtures/rssData.js (4)
1-43
: LGTM! Consider adding more edge cases.The
mockRssData
structure is well-designed for testing various scenarios, including featured and non-featured posts, different image formats, and consistent date formats.Consider adding more edge cases to enhance test coverage, such as:
- A post with an empty excerpt
- A post with a very long title or excerpt
- A post with special characters in the title or slug
63-72
: Good test case for incomplete posts. Consider expanding.The
incompletePostMockData
provides a valuable test case for handling posts with missing title attributes.Consider expanding this test case to include other scenarios of incomplete data, such as:
- A post missing an excerpt
- A post with an empty slug
This would provide more comprehensive coverage for error handling in the RSS builder.
74-77
: LGTM! Consider using an object for configuration.The constants
type
,title
,desc
, andoutputPath
provide clear configuration for the RSS feed generation.Consider grouping these configuration constants into a single object for better organization:
const rssConfig = { type: 'blog', title: 'Test Blog RSS', desc: 'Test blog RSS feed', outputPath: 'test-output/blog.xml' };This approach would make it easier to add or modify configuration options in the future.
79-79
: Consider reordering exports for consistency.The module exports include all necessary constants, which is good.
Consider reordering the exports to match the order of declaration in the file for better readability:
module.exports = { mockRssData, missingDateMockData, incompletePostMockData, type, title, desc, outputPath };This makes it easier to locate exported items when referencing the file.
scripts/build-rss.js (2)
57-58
: Enhance error messages with post identifiersWhen throwing an error due to missing required fields, including the post's identifier can help in debugging.
Modify the error message:
- throw new Error('Missing required fields in post data'); + throw new Error(`Missing required fields in post data for post: ${post.slug || post.title || 'unknown'}`);
67-72
: Simplify image type detection logicThe current logic checks for multiple image types using multiple
if
statements. Simplify it by using a mapping of extensions to MIME types.Refactor the code:
if (typeof enclosure["@url"] === 'string') { let tmp = enclosure["@url"].toLowerCase(); - if (tmp.indexOf('.png') >= 0) enclosure["@type"] = 'image/png'; - if (tmp.indexOf('.svg') >= 0) enclosure["@type"] = 'image/svg+xml'; - if (tmp.indexOf('.webp') >= 0) enclosure["@type"] = 'image/webp'; + const extension = tmp.split('.').pop().split('?')[0]; + const mimeTypes = { + png: 'image/png', + jpg: 'image/jpeg', + jpeg: 'image/jpeg', + svg: 'image/svg+xml', + webp: 'image/webp' + }; + enclosure["@type"] = mimeTypes[extension] || 'image/jpeg'; }This reduces code repetition and makes it easier to add support for more image types in the future.
tests/build-rss.test.js (1)
17-23
: Handle potential errors during cleanup inafterAll
When deleting files and directories during cleanup, it's good practice to handle potential errors to prevent tests from failing unexpectedly.
Example:
afterAll(() => { if (fs.existsSync(testOutputDir)) { fs.readdirSync(testOutputDir).forEach(file => { try { fs.unlinkSync(path.join(testOutputDir, file)); } catch (err) { console.error(`Error deleting file: ${file}`, err); } }); try { fs.rmdirSync(testOutputDir); } catch (err) { console.error(`Error removing directory: ${testOutputDir}`, err); } } });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (3)
- scripts/build-rss.js (2 hunks)
- tests/build-rss.test.js (1 hunks)
- tests/fixtures/rssData.js (1 hunks)
🔇 Additional comments (3)
tests/fixtures/rssData.js (2)
45-61
: Good test case for handling missing dates.The
missingDateMockData
provides a valuable test case for ensuring the RSS builder can handle posts with missing date attributes.
1-79
: Overall structure looks good. Indentation issues resolved.The file is well-structured with clear separation between different mock data sets. The indentation appears consistent throughout the file, addressing the concerns raised in previous reviews.
As mentioned in a previous review by @akshatnema, it's important to follow eslint rules. The current version of the file seems to adhere to consistent indentation practices, resolving the earlier concerns.
tests/build-rss.test.js (1)
100-110
: 🛠️ Refactor suggestionCheck for the existence of enclosure elements before assertions
Currently, the test assumes that all enclosure elements exist in the RSS feed. To prevent potential errors, ensure that the enclosure elements are present before making assertions on them.
Example:
const parser = require('fast-xml-parser'); const xmlData = fs.readFileSync(filePath, 'utf8'); const parsedData = parser.parse(xmlData); // Verify that each item has an enclosure parsedData.rss.channel.item.forEach(item => { expect(item.enclosure).toBeDefined(); });
throw new Error('Missing required fields in post data'); | ||
} | ||
const link = `${base}${post.slug}${tracking}`; | ||
const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve readability by destructuring and formatting
The construction of the item
object can be made more readable by destructuring post
and formatting the object properties.
Refactor as follows:
- const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() }
+ const { title, excerpt, date } = post;
+ const pubDate = new Date(date).toUTCString();
+ const description = clean(excerpt);
+ const guid = { '@isPermaLink': true, '': link };
+ const item = {
+ title,
+ description,
+ link,
+ category: type,
+ guid,
+ pubDate
+ };
This enhances readability and maintainability.
📝 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.
const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() } | |
const { title, excerpt, date } = post; | |
const pubDate = new Date(date).toUTCString(); | |
const description = clean(excerpt); | |
const guid = { '@isPermaLink': true, '': link }; | |
const item = { | |
title, | |
description, | |
link, | |
category: type, | |
guid, | |
pubDate | |
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vishvamsinh28 Apply this suggestion in the code.
There was a problem hiding this comment.
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!
return new Promise((resolve, reject) => { | ||
try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using asynchronous file operations with Promises
The function rssFeed
is now returning a Promise but still uses synchronous file operations like fs.writeFileSync
. To fully leverage asynchronous behavior and avoid blocking the event loop, consider using fs.writeFile
from the fs/promises
module.
Apply this change:
- const fs = require('fs')
+ const fs = require('fs').promises
...
- fs.writeFileSync(`./public/${outputPath}`, xml, 'utf8')
+ await fs.writeFile(`./public/${outputPath}`, xml, 'utf8')
Remember to make the function async
:
- module.exports = function rssFeed(type, title, desc, outputPath) {
+ module.exports = async function rssFeed(type, title, desc, outputPath) {
Committable suggestion was skipped due to low confidence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vishvamsinh28 apply this suggestion
There was a problem hiding this comment.
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!
}) | ||
|
||
if (i1.featured && !i2.featured) return -1 | ||
if (!i1.featured && i2.featured) return 1 | ||
return i2Date - i1Date | ||
}) | ||
const base = 'https://www.asyncapi.com' | ||
const tracking = '?utm_source=rss'; | ||
|
||
const base = 'https://www.asyncapi.com' | ||
const tracking = '?utm_source=rss'; | ||
const feed = {} | ||
const rss = {} | ||
rss['@version'] = '2.0' | ||
rss["@xmlns:atom"] = 'http://www.w3.org/2005/Atom' | ||
rss.channel = {} | ||
rss.channel.title = title | ||
rss.channel.link = `${base}/${outputPath}` | ||
rss.channel["atom:link"] = {} | ||
rss.channel["atom:link"]["@rel"] = 'self' | ||
rss.channel["atom:link"]["@href"] = rss.channel.link | ||
rss.channel["atom:link"]["@type"] = 'application/rss+xml' | ||
rss.channel.description = desc | ||
rss.channel.language = 'en-gb'; | ||
rss.channel.copyright = 'Made with :love: by the AsyncAPI Initiative.'; | ||
rss.channel.webMaster = 'info@asyncapi.io (AsyncAPI Initiative)' | ||
rss.channel.pubDate = new Date().toUTCString() | ||
rss.channel.generator = 'next.js' | ||
rss.channel.item = [] | ||
|
||
const feed = {} | ||
const rss = {} | ||
rss['@version'] = '2.0' | ||
rss["@xmlns:atom"] = 'http://www.w3.org/2005/Atom' | ||
rss.channel = {} | ||
rss.channel.title = title | ||
rss.channel.link = `${base}/${outputPath}` | ||
rss.channel["atom:link"] = {} | ||
rss.channel["atom:link"]["@rel"] = 'self' | ||
rss.channel["atom:link"]["@href"] = rss.channel.link | ||
rss.channel["atom:link"]["@type"] = 'application/rss+xml' | ||
rss.channel.description = desc | ||
rss.channel.language = 'en-gb'; | ||
rss.channel.copyright = 'Made with :love: by the AsyncAPI Initiative.'; | ||
rss.channel.webMaster = 'info@asyncapi.io (AsyncAPI Initiative)' | ||
rss.channel.pubDate = new Date().toUTCString() | ||
rss.channel.generator = 'next.js' | ||
rss.channel.item = [] | ||
|
||
for (let post of posts) { | ||
const link = `${base}${post.slug}${tracking}`; | ||
const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() } | ||
if (post.cover) { | ||
const enclosure = {}; | ||
enclosure["@url"] = base+post.cover; | ||
enclosure["@length"] = 15026; // dummy value, anything works | ||
enclosure["@type"] = 'image/jpeg'; | ||
if (typeof enclosure["@url"] === 'string') { | ||
let tmp = enclosure["@url"].toLowerCase(); | ||
if (tmp.indexOf('.png')>=0) enclosure["@type"] = 'image/png'; | ||
if (tmp.indexOf('.svg')>=0) enclosure["@type"] = 'image/svg+xml'; | ||
if (tmp.indexOf('.webp')>=0) enclosure["@type"] = 'image/webp'; | ||
for (let post of posts) { | ||
if (!post.title || !post.slug || !post.excerpt || !post.date) { | ||
throw new Error('Missing required fields in post data'); | ||
} | ||
const link = `${base}${post.slug}${tracking}`; | ||
const item = { title: post.title, description: clean(post.excerpt), link, category: type, guid: { '@isPermaLink': true, '': link }, pubDate: new Date(post.date).toUTCString() } | ||
if (post.cover) { | ||
const enclosure = {}; | ||
enclosure["@url"] = base + post.cover; | ||
enclosure["@length"] = 15026; // dummy value, anything works | ||
enclosure["@type"] = 'image/jpeg'; | ||
if (typeof enclosure["@url"] === 'string') { | ||
let tmp = enclosure["@url"].toLowerCase(); | ||
if (tmp.indexOf('.png') >= 0) enclosure["@type"] = 'image/png'; | ||
if (tmp.indexOf('.svg') >= 0) enclosure["@type"] = 'image/svg+xml'; | ||
if (tmp.indexOf('.webp') >= 0) enclosure["@type"] = 'image/webp'; | ||
} | ||
item.enclosure = enclosure; | ||
} | ||
rss.channel.item.push(item) | ||
} | ||
item.enclosure = enclosure; | ||
} | ||
rss.channel.item.push(item) | ||
} | ||
|
||
feed.rss = rss | ||
feed.rss = rss | ||
|
||
const xml = json2xml.getXml(feed,'@','',2) | ||
fs.writeFileSync(`./public/${outputPath}`, xml, 'utf8') | ||
const xml = json2xml.getXml(feed, '@', '', 2); | ||
fs.writeFileSync(`./public/${outputPath}`, xml, 'utf8') | ||
resolve(`RSS feed generated successfully at ${outputPath}`); | ||
} catch (err) { | ||
reject(new Error(`Failed to generate RSS feed: ${err.message}`)); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Leverage async/await for cleaner asynchronous code
By using async
/await
, the code becomes more readable and maintains the asynchronous behavior.
Modify the function definition and use await
:
- module.exports = function rssFeed(type, title, desc, outputPath) {
+ module.exports = async function rssFeed(type, title, desc, outputPath) {
Replace return new Promise
and the try...catch
block:
- return new Promise((resolve, reject) => {
- try {
...
- resolve(`RSS feed generated successfully at ${outputPath}`);
- } catch (err) {
- reject(new Error(`Failed to generate RSS feed: ${err.message}`));
- }
- });
+ try {
...
+ await fs.writeFile(`./public/${outputPath}`, xml, 'utf8');
+ return `RSS feed generated successfully at ${outputPath}`;
+ } catch (err) {
+ throw new Error(`Failed to generate RSS feed: ${err.message}`);
+ }
This refactoring streamlines the asynchronous operations and error handling.
Committable suggestion was skipped due to low confidence.
.sort((i1, i2) => { | ||
if (!i1.date || !i2.date) { | ||
throw new Error('Missing date in post data'); | ||
} | ||
const i1Date = new Date(i1.date) | ||
const i2Date = new Date(i2.date) | ||
if (i1.featured && !i2.featured) return -1 | ||
if (!i1.featured && i2.featured) return 1 | ||
return i2Date - i1Date | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid throwing errors inside the sort comparator function
Throwing an error within the comparator can disrupt the sorting process and lead to unexpected behavior. It's better to validate the data before sorting.
Refactor the code to filter out posts missing dates before sorting:
- const posts = getAllPosts()[`${type}`]
- .sort((i1, i2) => {
- if (!i1.date || !i2.date) {
- throw new Error('Missing date in post data');
- }
- const i1Date = new Date(i1.date)
- const i2Date = new Date(i2.date)
- if (i1.featured && !i2.featured) return -1
- if (!i1.featured && i2.featured) return 1
- return i2Date - i1Date
- })
+ let posts = getAllPosts()[`${type}`]
+ posts = posts.filter(post => {
+ if (!post.date) {
+ console.warn(`Post "${post.title || post.slug}" is missing a date and will be excluded.`);
+ return false;
+ }
+ return true;
+ });
+ posts.sort((i1, i2) => {
+ const i1Date = new Date(i1.date)
+ const i2Date = new Date(i2.date)
+ if (i1.featured && !i2.featured) return -1
+ if (!i1.featured && i2.featured) return 1
+ return i2Date - i1Date
+ })
This ensures the sorting function only handles valid data and improves robustness.
📝 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.
.sort((i1, i2) => { | |
if (!i1.date || !i2.date) { | |
throw new Error('Missing date in post data'); | |
} | |
const i1Date = new Date(i1.date) | |
const i2Date = new Date(i2.date) | |
if (i1.featured && !i2.featured) return -1 | |
if (!i1.featured && i2.featured) return 1 | |
return i2Date - i1Date | |
}) | |
let posts = getAllPosts()[`${type}`] | |
posts = posts.filter(post => { | |
if (!post.date) { | |
console.warn(`Post "${post.title || post.slug}" is missing a date and will be excluded.`); | |
return false; | |
} | |
return true; | |
}); | |
posts.sort((i1, i2) => { | |
const i1Date = new Date(i1.date) | |
const i2Date = new Date(i2.date) | |
if (i1.featured && !i2.featured) return -1 | |
if (!i1.featured && i2.featured) return 1 | |
return i2Date - i1Date | |
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vishvamsinh28 apply this suggestion in your code.
There was a problem hiding this comment.
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!
let error; | ||
try { | ||
await rssFeed(type, title, desc, outputPath); | ||
} catch (err) { | ||
error = err; | ||
} | ||
|
||
expect(error).toBeUndefined(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Simplify asynchronous tests using Jest's resolves
Instead of using a try/catch
block to handle the Promise, you can utilize Jest's expect().resolves
for cleaner and more readable tests.
Refactored code:
await expect(rssFeed(type, title, desc, outputPath)).resolves.not.toThrow();
This approach automatically handles the Promise resolution and failure.
let error; | ||
try { | ||
await rssFeed(type, title, desc, outputPath); | ||
} catch (err) { | ||
error = err; | ||
expect(error).toBeDefined(); | ||
expect(error.message).toContain('Missing required fields'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use Jest's rejects.toThrow
for expected errors
Simplify the test by asserting the Promise rejection directly.
Refactored code:
await expect(rssFeed(type, title, desc, outputPath)).rejects.toThrow('Missing required fields');
let error; | ||
try { | ||
await rssFeed(type, title, desc, outputPath); | ||
} catch (err) { | ||
error = err; | ||
expect(error).toBeDefined(); | ||
expect(error.message).toContain('Missing date in post data'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use Jest's rejects.toThrow
for expected errors
Enhance the test by using expect().rejects.toThrow()
.
Refactored code:
await expect(rssFeed(type, title, desc, outputPath)).rejects.toThrow('Missing date in post data');
const itemTitles = fileContent.match(/<title>(.*?)<\/title>/g); | ||
|
||
expect(error).toBeUndefined(); | ||
expect(itemTitles[1]).toContain('Test Post 1'); | ||
expect(itemTitles[2]).toContain('Another Featured Post'); | ||
expect(itemTitles[3]).toContain('Non-Featured Post 1'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use an XML parser instead of regex for parsing RSS feed
Parsing XML with regular expressions can be error-prone and brittle. Consider using an XML parser like xml2js
or fast-xml-parser
to reliably extract item titles from the RSS feed.
Example using fast-xml-parser
:
const parser = require('fast-xml-parser');
const xmlData = fs.readFileSync(filePath, 'utf8');
const parsedData = parser.parse(xmlData);
const itemTitles = parsedData.rss.channel.item.map(item => item.title);
// Now you can assert on itemTitles array
expect(itemTitles[0]).toContain('Test Post 1');
This approach ensures accurate parsing of RSS data regardless of formatting or additional whitespace.
const itemTitles = fileContent.match(/<title>(.*?)<\/title>/g); | ||
|
||
expect(error).toBeUndefined(); | ||
expect(itemTitles[1]).toContain('Test Post 1'); | ||
expect(itemTitles[2]).toContain('Another Featured Post'); | ||
expect(itemTitles[3]).toContain('Non-Featured Post 1'); | ||
expect(itemTitles[4]).toContain('Non-Featured Post 3'); | ||
expect(itemTitles[5]).toContain('Non-Featured Post 2'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use an XML parser instead of regex for parsing RSS feed
For consistent and reliable parsing of the RSS feed, utilize an XML parser.
Example using fast-xml-parser
:
const parser = require('fast-xml-parser');
const xmlData = fs.readFileSync(filePath, 'utf8');
const parsedData = parser.parse(xmlData);
const itemTitles = parsedData.rss.channel.item.map(item => item.title);
// Now you can assert on itemTitles array
expect(itemTitles[0]).toContain('Test Post 1');
This method avoids potential issues with regex parsing and handles XML structures appropriately.
afterEach(() => { | ||
jest.resetModules(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Reset mocks instead of modules in afterEach
Instead of using jest.resetModules()
, consider using jest.resetAllMocks()
or jest.clearAllMocks()
to reset your mocks between tests. This is generally more efficient and avoids unnecessary module resets.
Refactored code:
afterEach(() => {
jest.resetAllMocks();
});
}); | ||
|
||
afterEach(() => { | ||
jest.resetModules(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vishvamsinh28 any specific reason on why are we resetting all modules instead of mocks here?
This PR adds test for build-rss.js script
Summary by CodeRabbit
New Features
Bug Fixes
Documentation