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 test for combine tools script #3136

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions scripts/build-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ const manualTools = require('../config/tools-manual.json')
const fs = require('fs');
const { resolve } = require('path');

let toolsPath = resolve(__dirname, '../../config', 'tools.json')
Copy link
Member

Choose a reason for hiding this comment

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

is using let a good option here?

let tagsPath = resolve(__dirname, '../../config', 'all-tags.json')
let automatedToolsPath = resolve(__dirname, '../config', 'tools-automated.json')

const buildTools = async () => {
try {
let githubExtractData = await getData();
let automatedTools = await convertTools(githubExtractData);
fs.writeFileSync(
resolve(__dirname, '../config', 'tools-automated.json'),
automatedToolsPath,
JSON.stringify(automatedTools, null, ' ')
);
await combineTools(automatedTools, manualTools);
await combineTools(automatedTools, manualTools, toolsPath, tagsPath);
} catch (err) {
console.log(err);
throw err
Expand Down
13 changes: 3 additions & 10 deletions scripts/tools/combine-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const fs = require('fs')
const schema = require("./tools-schema.json");
const Ajv = require("ajv")
const addFormats = require("ajv-formats")
const { resolve } = require('path');
const Fuse = require("fuse.js");
const ajv = new Ajv()
addFormats(ajv, ["uri"])
Expand Down Expand Up @@ -106,7 +105,7 @@ const getFinalTool = async (toolObject) => {

// Combine the automated tools and manual tools list into single JSON object file, and
// lists down all the language and technology tags in one JSON file.
const combineTools = async (automatedTools, manualTools) => {
const combineTools = async (automatedTools, manualTools, toolsPath, tagsPath) => {
Copy link
Member

Choose a reason for hiding this comment

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

what does tagspath signify??

for (const key in automatedTools) {
let finalToolsList = [];
if (automatedTools[key].toolsList.length) {
Expand Down Expand Up @@ -136,14 +135,8 @@ const combineTools = async (automatedTools, manualTools) => {
finalToolsList.sort((tool, anotherTool) => tool.title.localeCompare(anotherTool.title));
finalTools[key].toolsList = finalToolsList
}
fs.writeFileSync(
resolve(__dirname, '../../config', 'tools.json'),
JSON.stringify(finalTools)
);
fs.writeFileSync(
resolve(__dirname, '../../config', 'all-tags.json'),
JSON.stringify({ languages: languageList, technologies: technologyList }),
)
fs.writeFileSync(toolsPath,JSON.stringify(finalTools));
fs.writeFileSync(tagsPath,JSON.stringify({ languages: languageList, technologies: technologyList }),)
}

module.exports = { combineTools }
Copy link
Member

Choose a reason for hiding this comment

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

fix this linter error

17 changes: 17 additions & 0 deletions tests/fixtures/tools/automated-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"category1": {
"description": "Sample Category",
"toolsList": [
{
"title": "Tool B",
"filters": {
"language": "Python",
"technology": ["Flask"]
},
"links": {
"repoUrl": "https://github.com/asyncapi/tool-b"
}
}
]
}
}
12 changes: 12 additions & 0 deletions tests/fixtures/tools/manual-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"title": "Tool A",
"filters": {
"language": "JavaScript",
"technology": ["Node.js"]
},
"links": {
"repoUrl": "https://github.com/asyncapi/tool-a"
}
}
]
187 changes: 187 additions & 0 deletions tests/tools/combine-tools.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
const fs = require('fs');
const path = require('path');
const { combineTools } = require('../../scripts/tools/combine-tools');
const { createToolObject } = require('../../scripts/tools/tools-object');

jest.mock('../../scripts/tools/tags-color', () => ({
languagesColor: [
{ name: 'JavaScript', color: 'bg-[#57f281]', borderColor: 'border-[#37f069]' },
{ name: 'Python', color: 'bg-[#3572A5]', borderColor: 'border-[#3572A5]' }
],
technologiesColor: [
{ name: 'Node.js', color: 'bg-[#61d0f2]', borderColor: 'border-[#40ccf7]' },
{ name: 'Flask', color: 'bg-[#000000]', borderColor: 'border-[#FFFFFF]' }
]
}));

jest.mock('../../scripts/tools/categorylist', () => ({
categoryList: [
{ name: 'category1', description: 'Sample Category 1' },
{ name: 'category2', description: 'Sample Category 2' }
]
}));

jest.mock('../../scripts/tools/tools-object', () => ({
createToolObject: jest.fn((tool, _, __, isAsyncAPIrepo) => {
return { ...tool, isAsyncAPIrepo };
})
}));

const readJSON = (filePath) => JSON.parse(fs.readFileSync(filePath, 'utf-8'));

describe('combineTools function', () => {
const toolsPath = path.join(__dirname, '../', 'fixtures', 'tools', 'tools.json');
const tagsPath = path.join(__dirname, '../', 'fixtures', 'tools', 'tags.json');
const manualToolsPath = path.join(__dirname, '../', 'fixtures', 'tools', 'manual-tools.json');
const automatedToolsPath = path.join(__dirname, '../', 'fixtures', 'tools', 'automated-tools.json');

let manualTools;
let automatedTools;

let consoleErrorMock;

beforeAll(() => {
manualTools = readJSON(manualToolsPath);
automatedTools = readJSON(automatedToolsPath);

consoleErrorMock = jest.spyOn(console, 'error').mockImplementation(() => {});
});

afterAll(() => {
if (fs.existsSync(toolsPath)) fs.unlinkSync(toolsPath);
if (fs.existsSync(tagsPath)) fs.unlinkSync(tagsPath);
});

it('should combine tools and create correct JSON files', async () => {
await combineTools(automatedTools, manualTools, toolsPath, tagsPath);
Copy link
Member

Choose a reason for hiding this comment

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

try to add this function call in a try/catch block here to monitor if we are receiving any error or not.


const combinedTools = readJSON(toolsPath);
expect(combinedTools).toHaveProperty('category1');

const tagsData = readJSON(tagsPath);
expect(tagsData).toHaveProperty('languages');
expect(tagsData).toHaveProperty('technologies');
expect(tagsData.languages).toContainEqual({
name: 'JavaScript',
color: 'bg-[#57f281]',
borderColor: 'border-[#37f069]'
});
expect(tagsData.languages).toContainEqual({
name: 'Python',
color: 'bg-[#3572A5]',
borderColor: 'border-[#3572A5]'
});
expect(tagsData.technologies).toContainEqual({
name: 'Node.js',
color: 'bg-[#61d0f2]',
borderColor: 'border-[#40ccf7]'
});
expect(tagsData.technologies).toContainEqual({
name: 'Flask',
color: 'bg-[#000000]',
borderColor: 'border-[#FFFFFF]'
});
});

it('should handle tools with missing language or technology', async () => {
const manualToolsWithMissingData = [
{
title: 'Tool C',
filters: {},
links: { repoUrl: 'https://github.com/asyncapi/tool-c' }
}
];

await combineTools({}, manualToolsWithMissingData, toolsPath, tagsPath);

const combinedTools = readJSON(toolsPath);
expect(combinedTools).toHaveProperty('category1');
});

it('should sort tools alphabetically by title', async () => {
const manualToolsToSort = {
category1: {
description: 'Sample Category',
toolsList: [
{
title: 'Tool Z',
filters: { language: 'JavaScript' },
links: { repoUrl: 'https://github.com/asyncapi/tool-z' }
},
{
title: 'Tool A',
filters: { language: 'Python' },
links: { repoUrl: 'https://github.com/asyncapi/tool-a' }
}
]
}
};

await combineTools(manualToolsToSort, {}, toolsPath, tagsPath);

const combinedTools = readJSON(toolsPath);
const toolTitles = combinedTools.category1.toolsList.map(tool => tool.title);
expect(toolTitles).toEqual(['Tool A', 'Tool Z']);
});


it('should log validation errors to console.error', async () => {
Copy link
Member

Choose a reason for hiding this comment

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

Errors shouldn't be validated via console messages. You should formally return a error using Promise.reject.

const invalidTool = { title: 'Invalid Tool' };
const automatedTools = {
'category1': {
description: 'Category 1 Description',
toolsList: []
}
};
const manualTools = {
'category1': {
toolsList: [invalidTool]
}
};

createToolObject.mockImplementation((tool) => Promise.resolve(tool));

await combineTools(automatedTools, manualTools, toolsPath, tagsPath);

const errorCalls = console.error.mock.calls;

expect(errorCalls[0][0]).toBe('Script is not failing, it is just dropping errors for further investigation');
expect(errorCalls[1][0]).toBe('Invalid Invalid Tool .asyncapi-tool file.');
expect(errorCalls[2][0]).toBe('Located in manual-tools.json file');
expect(errorCalls[3][0]).toEqual(expect.stringContaining('Validation errors:'));

expect(fs.existsSync(toolsPath)).toBe(true);
expect(fs.existsSync(tagsPath)).toBe(true);
});

it('should handle tools with multiple languages, including new ones', async () => {
const toolWithMultipleLanguages = {
title: 'Multi-Language Tool',
filters: {
language: ['JavaScript', 'Python', 'NewLanguage'],
technology: ['Node.js']
},
links: { repoUrl: 'https://github.com/example/multi-language-tool' }
};

const automatedTools = {
'category1': {
description: 'Category 1 Description',
toolsList: [toolWithMultipleLanguages]
}
};

await combineTools(automatedTools, {}, toolsPath, tagsPath);

const combinedTools = readJSON(toolsPath);
const tool = combinedTools.category1.toolsList[0];

expect(tool.filters.language).toHaveLength(3);
expect(tool.filters.language).toContainEqual(expect.objectContaining({ name: 'JavaScript' }));
expect(tool.filters.language).toContainEqual(expect.objectContaining({ name: 'Python' }));
expect(tool.filters.language).toContainEqual(expect.objectContaining({ name: 'NewLanguage' }));

const tagsData = readJSON(tagsPath);
expect(tagsData.languages).toContainEqual(expect.objectContaining({ name: 'NewLanguage' }));
});
});
Copy link
Member

Choose a reason for hiding this comment

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

fix this one also

Loading