Skip to content
Open
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
104 changes: 104 additions & 0 deletions tests/compose.test.ts
Original file line number Diff line number Diff line change
@@ -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


jest.mock('inquirer', () => ({
prompt: jest.fn()
}));

jest.mock('fs', () => ({
writeFile: jest.fn()
}));

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

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


jest.mock('../scripts/helpers/logger', () => ({
logger: {
info: jest.fn(),
error: jest.fn()
}
}));

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


describe('compose script', () => {
const defaultAnswers = {
title: 'My First Blog Post!',
excerpt: 'A test excerpt for the blog post.',
tags: 'asyncapi, tutorial',
type: 'Engineering',
canonical: 'https://example.com'
};

let promptMock: jest.Mock;
let writeFileMock: jest.Mock;
let loggerInfoMock: jest.Mock;
let loggerErrorMock: jest.Mock;

beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();

// 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;
Comment on lines +45 to +52

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

});

it('generates the blog post file with front matter for the happy path', async () => {
promptMock.mockResolvedValue(defaultAnswers);
writeFileMock.mockImplementation((_filePath, _content, _options, callback) => callback(null));

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('../scripts/compose');
await flushPromises();

expect(writeFileMock).toHaveBeenCalledTimes(1);
const [filePath, content, options] = writeFileMock.mock.calls[0];

expect(filePath).toBe('pages/blog/my-first-blog-post.md');
expect(options).toEqual({ flag: 'wx' });
expect(content).toContain('title: My First Blog Post!');
expect(content).toContain("tags: ['asyncapi','tutorial']");
expect(content).toContain('date: 2021-05-01T10:00:00+02:00');
expect(content).toContain('canonical: https://example.com');
expect(loggerInfoMock).toHaveBeenCalledWith('Blog post generated successfully at pages/blog/my-first-blog-post.md');
});

it.each([
['Hello World??', 'pages/blog/hello-world.md'],
['My-Second_Post (v2)', 'pages/blog/mysecondpost-v2.md'],
['', 'pages/blog/untitled.md'],
['!!!', 'pages/blog/untitled.md']
])('slugifies the title "%s" into the file path "%s"', async (title, expectedPath) => {
promptMock.mockResolvedValue({ ...defaultAnswers, title });
writeFileMock.mockImplementation((_filePath, _content, _options, callback) => callback(null));

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('../scripts/compose');
await flushPromises();

expect(writeFileMock).toHaveBeenCalledTimes(1);
expect(writeFileMock.mock.calls[0][0]).toBe(expectedPath);
});

it('logs an error when the file cannot be written', async () => {
promptMock.mockResolvedValue(defaultAnswers);
writeFileMock.mockImplementation((_filePath, _content, _options, callback) => callback(new Error('EEXIST')));

Comment on lines +92 to +95

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.

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('../scripts/compose');
await flushPromises();

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

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

});
});
Loading