Skip to content

test: add unit tests for scripts/compose.ts - #5685

Open
qwe123456789zxc wants to merge 1 commit into
asyncapi:masterfrom
qwe123456789zxc:test/compose-tests
Open

test: add unit tests for scripts/compose.ts#5685
qwe123456789zxc wants to merge 1 commit into
asyncapi:masterfrom
qwe123456789zxc:test/compose-tests

Conversation

@qwe123456789zxc

@qwe123456789zxc qwe123456789zxc commented Aug 3, 2026

Copy link
Copy Markdown

What changed

Adds Jest unit tests for the blog post composition script (scripts/compose.ts), covering the interactive CLI flow and file generation behavior, as requested in #5096.

  • Happy path: verifies the generated file path, front matter content (title, tags, canonical, date) and the success log message.
  • Slug generation: verifies that titles are normalized to kebab-case file names, including empty and special-character-only titles falling back to \untitled.
  • Error handling: verifies the error is logged when the file cannot be written.

How it works

The script runs its inquirer prompt chain at module load, so the tests mock \inquirer, \ s, \dayjs, and the logger, then import the script and flush the promise chain. Deterministic date via a mocked \dayjs.

Testing

Ran locally with jest: 6 tests passing.

Certification

  • I changed only test files (tests/compose.test.ts).
  • My commits include a Signed-off-by line.

Summary by CodeRabbit

  • Tests
    • Added comprehensive automated coverage for the content composition workflow.
    • Verified successful blog post generation with mocked dependencies.
    • Added validation for converting post titles into URL-friendly slugs.
    • Added coverage for handling and logging file-write errors.
    • Improved confidence that content generation behaves consistently across success and failure scenarios.

Signed-off-by: qwe123456789zxc <95130171+qwe123456789zxc@users.noreply.github.com>
@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 5e7245f
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/6a7078f058d16e00080b46a2
😎 Deploy Preview https://deploy-preview-5685--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Welcome to AsyncAPI. Thanks a lot for creating your first pull request. Please check out our contributors guide useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out this issue.

@sonarqubecloud

sonarqubecloud Bot commented Aug 3, 2026

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Added Jest tests for the compose script. The tests mock dependencies, verify successful blog post generation, validate title slugification cases, and confirm file-write errors are logged.

Changes

Compose script tests

Layer / File(s) Summary
Compose test harness
tests/compose.test.ts
Mocks inquirer, fs, dayjs, and the logger. Adds shared fixtures and asynchronous test setup.
Generation and error-path coverage
tests/compose.test.ts
Verifies generated file content, paths, timestamps, canonical URLs, success logging, title slugification, and file-write error logging.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • asyncapi/website#5096 — Covers the same compose script test areas, including slug generation, file writing, and error handling.

Suggested reviewers: akshatnema, anshgoyalevil, asyncapi-bot-eve

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the added unit tests for scripts/compose.ts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@asyncapi-bot

Copy link
Copy Markdown
Contributor

⚡️ Lighthouse report for the changes in this PR:

Category Score
🟠 Performance 70
🟢 Accessibility 98
🟢 Best practices 92
🟢 SEO 100
🔴 PWA 33

Lighthouse ran on https://deploy-preview-5685--asyncapi-website.netlify.app/

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/compose.test.ts`:
- Around line 45-52: Update every affected dynamic require in the test setup,
including the statements assigning promptMock, writeFileMock, loggerInfoMock,
and loggerErrorMock and the additional occurrences, so each ESLint directive
also suppresses global-require alongside `@typescript-eslint/no-var-requires`;
alternatively, replace them with a lint-approved mock accessor.
- Around line 101-102: Insert a blank line between the errorArg declaration and
the following expect assertion in the relevant test block to satisfy ESLint’s
required statement padding.
- Around line 11-16: Update the Day.js mock factory in jest.mock by adding a
blank line between the dayjsMock declaration and the return dayjsMock statement
to satisfy the padding lint rule.
- Line 25: Update the flushPromises helper’s Promise executor to use a block
body and invoke setImmediate without returning its handle, while preserving the
existing promise-resolution behavior.
- Line 1: Remove the unused logger import from tests/compose.test.ts; keep the
mocked logger access through the existing module lookup around the referenced
test lines unchanged.
- Around line 92-95: Update the writeFileMock setup in the “logs an error when
the file cannot be written” test to invoke its callback asynchronously, matching
fs.writeFile timing, and await/drain the resulting promise before assertions so
the callback error is observed without an unhandled throw.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3aaf1e2d-2f91-4fd4-8134-610fbd8fece9

📥 Commits

Reviewing files that changed from the base of the PR and between 1a4120e and 5e7245f.

📒 Files selected for processing (1)
  • tests/compose.test.ts

Comment thread tests/compose.test.ts
@@ -0,0 +1,104 @@
import { logger } from '../scripts/helpers/logger';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the unused logger import.

The test accesses the mocked logger through the module lookup on Lines 50-52. The top-level import has no consumer and triggers the reported unused-import rules.

Proposed fix
-import { logger } from '../scripts/helpers/logger';
📝 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
import { logger } from '../scripts/helpers/logger';
🧰 Tools
🪛 ESLint

[error] 1-1: 'logger' is defined but never used. Allowed unused vars must match /^_/u.

(no-unused-vars)


[error] 1-1: 'logger' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 1-1: 'logger' is defined but never used.

(unused-imports/no-unused-imports)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` at line 1, Remove the unused logger import from
tests/compose.test.ts; keep the mocked logger access through the existing module
lookup around the referenced test lines unchanged.

Source: Linters/SAST tools

Comment thread tests/compose.test.ts
Comment on lines +11 to +16
jest.mock('dayjs', () => {
const dayjsMock = jest.fn(() => ({
format: jest.fn(() => '2021-05-01T10:00:00+02:00')
}));
return dayjsMock;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the padding lint errors in the Day.js mock.

Add a blank line after the dayjsMock declaration and before return dayjsMock.

Proposed fix
   const dayjsMock = jest.fn(() => ({
     format: jest.fn(() => '2021-05-01T10:00:00+02:00')
   }));
+
   return dayjsMock;
📝 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
jest.mock('dayjs', () => {
const dayjsMock = jest.fn(() => ({
format: jest.fn(() => '2021-05-01T10:00:00+02:00')
}));
return dayjsMock;
});
jest.mock('dayjs', () => {
const dayjsMock = jest.fn(() => ({
format: jest.fn(() => '2021-05-01T10:00:00+02:00')
}));
return dayjsMock;
});
🧰 Tools
🪛 ESLint

[error] 12-14: Expected blank line after variable declarations.

(newline-after-var)


[error] 15-15: Expected blank line before this statement.

(padding-line-between-statements)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` around lines 11 - 16, Update the Day.js mock factory
in jest.mock by adding a blank line between the dayjsMock declaration and the
return dayjsMock statement to satisfy the padding lint rule.

Source: Linters/SAST tools

Comment thread tests/compose.test.ts
}
}));

const flushPromises = () => new Promise((resolve) => setImmediate(resolve));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use a block-bodied promise executor.

The expression-bodied executor returns the setImmediate handle. This triggers no-promise-executor-return.

Proposed fix
-const flushPromises = () => new Promise((resolve) => setImmediate(resolve));
+const flushPromises = () =>
+  new Promise<void>((resolve) => {
+    setImmediate(resolve);
+  });
📝 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 flushPromises = () => new Promise((resolve) => setImmediate(resolve));
const flushPromises = () =>
new Promise<void>((resolve) => {
setImmediate(resolve);
});
🧰 Tools
🪛 ESLint

[error] 25-25: Return values from promise executor functions cannot be read.

(no-promise-executor-return)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` at line 25, Update the flushPromises helper’s Promise
executor to use a block body and invoke setImmediate without returning its
handle, while preserving the existing promise-resolution behavior.

Source: Linters/SAST tools

Comment thread tests/compose.test.ts
Comment on lines +45 to +52
// eslint-disable-next-line @typescript-eslint/no-var-requires
promptMock = require('inquirer').prompt;
// eslint-disable-next-line @typescript-eslint/no-var-requires
writeFileMock = require('fs').writeFile;
// eslint-disable-next-line @typescript-eslint/no-var-requires
loggerInfoMock = require('../scripts/helpers/logger').logger.info;
// eslint-disable-next-line @typescript-eslint/no-var-requires
loggerErrorMock = require('../scripts/helpers/logger').logger.error;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the ESLint suppression for dynamic mock access.

The directives suppress only @typescript-eslint/no-var-requires. Static analysis reports global-require for these same statements. Add global-require to each directive, or replace the dynamic imports with a lint-approved mock accessor.

Proposed fix
-    // eslint-disable-next-line `@typescript-eslint/no-var-requires`
+    // eslint-disable-next-line `@typescript-eslint/no-var-requires`, global-require

Apply this change to each affected require statement.

Also applies to: 59-60, 84-85, 96-97

🧰 Tools
🪛 ESLint

[error] 46-46: Unexpected require().

(global-require)


[error] 48-48: Unexpected require().

(global-require)


[error] 50-50: Unexpected require().

(global-require)


[error] 52-52: Unexpected require().

(global-require)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` around lines 45 - 52, Update every affected dynamic
require in the test setup, including the statements assigning promptMock,
writeFileMock, loggerInfoMock, and loggerErrorMock and the additional
occurrences, so each ESLint directive also suppresses global-require alongside
`@typescript-eslint/no-var-requires`; alternatively, replace them with a
lint-approved mock accessor.

Source: Linters/SAST tools

Comment thread tests/compose.test.ts
Comment on lines +92 to +95
it('logs an error when the file cannot be written', async () => {
promptMock.mockResolvedValue(defaultAnswers);
writeFileMock.mockImplementation((_filePath, _content, _options, callback) => callback(new Error('EEXIST')));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 12 'fs\.writeFile|throw err|logger\.error|\.catch' scripts/compose.ts
rg -n -C 6 'writeFileMock|callback\(new Error|flushPromises' tests/compose.test.ts

Repository: asyncapi/website

Length of output: 4485


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
function flushPromises() {
  return new Promise((resolve) => setImmediate(resolve));
}

let caught = false;
const actualCallback = () => {
  setTimeout(() => {
    throw new Error('EEXIST');
  }, 0);
};

Promise.resolve().then(() => {
  actualCallback();
  return flushPromises();
}).catch(() => {
  caught = true;
});

flushPromises()
  .then(() => {
    const resolvedBeforeLaterCallback = !caught;
    return flushPromises();
  })
  .then(() => {
    console.log(JSON.stringify({ caughtWhenCallbackRunsLater: caught }));
  });
JS

Repository: asyncapi/website

Length of output: 384


Make the write-error mock match fs.writeFile callback timing.

scripts/compose.ts expects fs.writeFile callback errors to be observed inside the promise handler. The current test passes by synchronously calling callback(new Error('EEXIST')), while real fs.writeFile schedules callbacks later. Either invoke the test callback asynchronously, drain promises until the callback error is observed, or change production code to reject/recover from callback errors so the later async callback does not leave an unhandled throw.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` around lines 92 - 95, Update the writeFileMock setup
in the “logs an error when the file cannot be written” test to invoke its
callback asynchronously, matching fs.writeFile timing, and await/drain the
resulting promise before assertions so the callback error is observed without an
unhandled throw.

Comment thread tests/compose.test.ts
Comment on lines +101 to +102
const errorArg = loggerErrorMock.mock.calls.find((call) => call[0] instanceof Error)?.[0] as Error;
expect(errorArg.message).toBe('EEXIST');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the blank line required after errorArg.

ESLint reports missing padding before the following assertion.

Proposed fix
     const errorArg = loggerErrorMock.mock.calls.find((call) => call[0] instanceof Error)?.[0] as Error;
+
     expect(errorArg.message).toBe('EEXIST');
📝 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 errorArg = loggerErrorMock.mock.calls.find((call) => call[0] instanceof Error)?.[0] as Error;
expect(errorArg.message).toBe('EEXIST');
const errorArg = loggerErrorMock.mock.calls.find((call) => call[0] instanceof Error)?.[0] as Error;
expect(errorArg.message).toBe('EEXIST');
🧰 Tools
🪛 ESLint

[error] 101-101: Expected blank line after variable declarations.

(newline-after-var)


[error] 102-102: Expected blank line before this statement.

(padding-line-between-statements)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/compose.test.ts` around lines 101 - 102, Insert a blank line between
the errorArg declaration and the following expect assertion in the relevant test
block to satisfy ESLint’s required statement padding.

Source: Linters/SAST tools

@SHUBHANSHU602

Copy link
Copy Markdown
Contributor

@qwe123456789zxc Please have alook at coderabbit suggestion , also CI checks are failing because of linting and other errors so have a look at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Be Triaged

Development

Successfully merging this pull request may close these issues.

3 participants