Skip to content
Merged
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
566 changes: 74 additions & 492 deletions .jest-skip/labeler-utils.test.js

Large diffs are not rendered by default.

65 changes: 21 additions & 44 deletions .jest-skip/validate-coderabbit-yml.test.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,34 @@
// validate-coderabbit-yml.test.js
// Jest test for validate-coderabbit-yml.cjs

const { execSync } = require("child_process");
const fs = require("fs");
/**
* @jest-environment jsdom
*/
const path = require("path");
const { execSync } = require("child_process");

describe("validate-coderabbit-yml.cjs", () => {
const scriptPath = path.resolve(__dirname, "../validate-coderabbit-yml.cjs");
const ymlPath = path.resolve(__dirname, "../../../.coderabbit.yml");
const backupPath = ymlPath + ".bak";

beforeAll(() => {
// Backup the original .coderabbit.yml if it exists
if (fs.existsSync(ymlPath)) {
fs.copyFileSync(ymlPath, backupPath);
}
// Write a minimal valid .coderabbit.yml
fs.writeFileSync(
ymlPath,
'reviews:\n path_filters: ["src/"]\n auto_review: true\n',
describe("Coderabbit YML Validation", () => {
it("should validate a correct coderabbit.yml file", () => {
const script = path.resolve(__dirname, "../validate-coderabbit-yml.cjs");
const file = path.resolve(
__dirname,
"../__fixtures__/valid-coderabbit.yml",
);
const result = execSync(`node ${script} ${file}`, { encoding: "utf8" });
expect(result).toMatch(/\.coderabbit\.yml is valid!/i);
});

afterAll(() => {
// Restore the original .coderabbit.yml
if (fs.existsSync(backupPath)) {
fs.copyFileSync(backupPath, ymlPath);
fs.unlinkSync(backupPath);
} else {
fs.unlinkSync(ymlPath);
}
});

it("validates a correct .coderabbit.yml and exits 0", () => {
let output = "";
expect(() => {
output = execSync(`node ${scriptPath}`, { encoding: "utf8" });
}).not.toThrow();
expect(output).toMatch(/\.coderabbit\.yml is valid!/);
});

it("fails if required field is missing", () => {
// Write an invalid .coderabbit.yml (missing reviews)
fs.writeFileSync(ymlPath, "notreviews: true\n");
it("should fail on an invalid coderabbit.yml file", () => {
const script = path.resolve(__dirname, "../validate-coderabbit-yml.cjs");
const file = path.resolve(
__dirname,
"../__fixtures__/invalid-coderabbit.yml",
);
let error = null;
try {
execSync(`node ${scriptPath}`, { encoding: "utf8", stdio: "pipe" });
execSync(`node ${script} ${file}`, { encoding: "utf8" });
} catch (e) {
error = e;
}
expect(error).toBeTruthy();
expect(error.stdout || error.message).toMatch(
/Missing required top-level field: reviews/,
);
expect(error.stdout).toMatch(/Invalid \.coderabbit\.yml/i);
expect(error.stderr).toMatch(/Missing required top-level field: reviews/);
});
});
10 changes: 5 additions & 5 deletions .jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@ require('dotenv').config();
module.exports = {
// Switch to jsdom to provide window/localStorage, mitigating the SecurityError seen under node.
testEnvironment: process.env.JEST_ENVIRONMENT || 'jsdom',
// Provide a setup file that polyfills localStorage (defensive if environment overridden).
// NOTE: Temporarily disabled due to jest config resolution issue
// setupFilesAfterEnv: [
// '<rootDir>/tests/jest.setup.localstorage.js',
// ],
// Provide setup files for global polyfills (TextDecoder, localStorage)
setupFilesAfterEnv: [
'<rootDir>/tests/jest.setup.globals.js',
],
globals: {
'babel-jest': {
useESM: true,
Expand Down Expand Up @@ -67,6 +66,7 @@ module.exports = {
'<rootDir>/.vercel/',
'<rootDir>/.netlify/',
'<rootDir>/.storybook/',
'<rootDir>/.jest-skip/',

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: List all test files currently in .jest-skip/ directory

# Find all test files in .jest-skip/
fd -e test.js -e test.ts . '.jest-skip/' --type f

Repository: lightspeedwp/.github

Length of output: 1078


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== .jest.config.cjs: around line 70 =="
nl -ba .jest.config.cjs | sed -n '55,90p'

echo
echo "== References to .jest-skip/ =="
rg -n "\\.jest-skip/" -S . || true

Repository: lightspeedwp/.github

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== .jest.config.cjs: around line 70 =="
awk 'NR>=55 && NR<=90 {printf "%5d:%s\n", NR, $0}' .jest.config.cjs

echo
echo "== References to .jest-skip/ =="
rg -n "\\.jest-skip/" -S . || true

Repository: lightspeedwp/.github

Length of output: 1970


🌐 Web query:

Jest API test.failing() exists?

💡 Result:

Yes, the test.failing method exists in Jest and is supported [1]. This method allows you to define a test that is expected to fail; if the test throws an error or rejects, Jest considers it a passing test, whereas if the test passes unexpectedly, Jest will mark it as a failure [1][2]. This feature is often used to document known bugs or to TDD (Test Driven Development) a fix for an issue where the test currently fails [2]. It is similar to functionality found in other test runners like AVA or pytest [2]. If you are trying to verify that a specific function throws an error or rejects a promise rather than declaring an entire test as failing, you should use Jest's built-in assertion matchers instead, such as.toThrow or.rejects [3][4].

Citations:


Avoid hiding failing Jest tests via .jest-skip/
testPathIgnorePatterns in .jest.config.cjs ignores <rootDir>/.jest-skip/, so those tests are completely invisible to CI. Right now .jest-skip/ contains 28 *.test.js/ts files (e.g. planner.agent.test.js, reviewer.agent.test.js, validate-structure.test.js), and the repo’s own planning docs track this as “Tests disabled” with an explicit issue to move them out—so this is a real reliability gap, not just a temporary tidy-up.

For known failures, keep them visible in the suite instead:

  • describe.skip() / test.skip() inline with a clear TODO + linked issue
  • test.failing() when you intentionally expect a failure
  • Otherwise, fix the underlying tests and re-enable them by moving them to the normal Jest locations
🤖 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 @.jest.config.cjs at line 70, The Jest config currently hides tests by adding
'<rootDir>/.jest-skip/' to testPathIgnorePatterns; remove that ignore entry and
reintroduce the skipped tests so CI runs them, then for each failing test file
in .jest-skip (e.g. planner.agent.test.js, reviewer.agent.test.js,
validate-structure.test.js) either move the tests back into normal test
locations or convert failing cases to explicit skips using
describe.skip()/test.skip() with a TODO and issue link or use test.failing()
when appropriate; update any references to testPathIgnorePatterns in the
.jest.config.cjs and ensure CI runs the re-enabled tests.

'<rootDir>/docs/mustache-repo-templates/',
],
};
97 changes: 0 additions & 97 deletions scripts/agents/includes/__tests__/labeler-utils.test.js

This file was deleted.

135 changes: 135 additions & 0 deletions scripts/agents/includes/categoryMapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#!/usr/bin/env node
/**
* ============================================================================
* Module: categoryMapper.js
* Location: scripts/agents/includes/categoryMapper.js
* Description:
* - Maps commit types and PR labels to changelog sections
* - Provides bi-directional mapping between conventional commits and Keep a Changelog
* Standards:
* - Follows LightSpeed Coding Standards
* ============================================================================
*/

// Mapping from conventional commit types to Keep a Changelog sections
const TYPE_TO_SECTION = {
feat: "added",
fix: "fixed",
docs: "documentation",
style: "changed",
refactor: "changed",
perf: "performance",
test: "changed",
chore: "changed",
};

// Mapping from GitHub PR labels to changelog sections
const LABEL_TO_SECTION = {
"type: feature": "added",
"type: bugfix": "fixed",
"type: documentation": "documentation",
"type: breaking": "changed",
"type: deprecation": "deprecated",
"type: enhancement": "changed",
"type: security": "security",
"type: performance": "performance",
"priority: critical": "security",
"priority: high": "changed",
};
Comment on lines +27 to +38

// Reverse mappings for convenience
const SECTION_TO_TYPES = {};
Object.entries(TYPE_TO_SECTION).forEach(([type, section]) => {
if (!SECTION_TO_TYPES[section]) {
SECTION_TO_TYPES[section] = [];
}
SECTION_TO_TYPES[section].push(type);
});

const SECTION_TO_LABELS = {};
Object.entries(LABEL_TO_SECTION).forEach(([label, section]) => {
if (!SECTION_TO_LABELS[section]) {
SECTION_TO_LABELS[section] = [];
}
SECTION_TO_LABELS[section].push(label);
});

/**
* Map commit type to changelog section
* @param {string} type - Conventional commit type
* @returns {string|null} Changelog section name or null if unmapped
*/
function mapCommitTypeToSection(type) {
return TYPE_TO_SECTION[type?.toLowerCase()] || null;
}

/**
* Map PR label to changelog section
* @param {string} label - GitHub PR label
* @returns {string|null} Changelog section name or null if unmapped
*/
function mapLabelToSection(label) {
return LABEL_TO_SECTION[label?.toLowerCase()] || null;
}

/**
* Determine changelog section from commit and labels
* Priority: PR labels > Commit type
* @param {string} type - Conventional commit type
* @param {string[]} labels - PR labels
* @returns {string|null} Changelog section name
*/
function determineSection(type, labels = []) {
function determineSection(type, labels = []) {
Comment on lines +82 to +83

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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the duplicated function header is present and adjacent.
sed -n '78,98p' scripts/agents/includes/categoryMapper.js
rg -n '^function determineSection\(type, labels = \[\]\) \{$' scripts/agents/includes/categoryMapper.js

Repository: lightspeedwp/.github

Length of output: 716


🏁 Script executed:

rg -n '^function determineSection\(type, labels = \[\]\) \{$' scripts/agents/includes/categoryMapper.js
node --check scripts/agents/includes/categoryMapper.js

Repository: lightspeedwp/.github

Length of output: 363


Fix parse-breaking duplicate determineSection header (syntax error)

categoryMapper.js declares function determineSection(type, labels = []) { twice on adjacent lines (82–83), and node --check fails with SyntaxError: Unexpected end of input—the module won’t parse correctly.

🛠️ Proposed fix
 function determineSection(type, labels = []) {
-function determineSection(type, labels = []) {
  	// Check labels first (higher priority)
  	const safeLabels = Array.isArray(labels) ? labels : [];
  	for (const label of safeLabels) {
  		const section = mapLabelToSection(label);
  		if (section) return section;
  	}
📝 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
function determineSection(type, labels = []) {
function determineSection(type, labels = []) {
function determineSection(type, labels = []) {
// Check labels first (higher priority)
const safeLabels = Array.isArray(labels) ? labels : [];
for (const label of safeLabels) {
const section = mapLabelToSection(label);
if (section) return section;
}
🤖 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 `@scripts/agents/includes/categoryMapper.js` around lines 82 - 83, There is a
duplicate function header for determineSection(type, labels = []) causing a
parse error; remove the redundant declaration so only a single function named
determineSection remains and verify its opening brace matches the existing
function body and closing brace, ensuring no leftover duplicate line or
mismatched braces in categoryMapper.js.

// Check labels first (higher priority)
const safeLabels = Array.isArray(labels) ? labels : [];
for (const label of safeLabels) {
const section = mapLabelToSection(label);
if (section) return section;
}

// Fall back to commit type
if (type) {
return mapCommitTypeToSection(type);
}

return null;
}
Comment thread
ashleyshaw marked this conversation as resolved.
Comment on lines +82 to +97

/**
* Get all changelog section names
* @returns {string[]} Array of valid section names
*/
function getAllSections() {
return [
"added",
"changed",
"deprecated",
"removed",
"fixed",
"security",
"documentation",
"performance",
];
}

/**
* Check if section is valid
* @param {string} section - Section name
* @returns {boolean} True if section is valid
*/
function isValidSection(section) {
return getAllSections().includes(section?.toLowerCase());
}

module.exports = {
mapCommitTypeToSection,
mapLabelToSection,
determineSection,
getAllSections,
isValidSection,
TYPE_TO_SECTION,
LABEL_TO_SECTION,
SECTION_TO_TYPES,
SECTION_TO_LABELS,
};
Loading
Loading