Skip to content

chore(eslint): require descriptive messages on boolean test assertions#8537

Merged
watson merged 5 commits into
masterfrom
watson/eslint-boolean-assert-rule
May 21, 2026
Merged

chore(eslint): require descriptive messages on boolean test assertions#8537
watson merged 5 commits into
masterfrom
watson/eslint-boolean-assert-rule

Conversation

@watson

@watson watson commented May 19, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds a custom ESLint rule, eslint-rules/eslint-require-boolean-assert-message, that requires a descriptive message argument on boolean test assertions — assert(value) and assert.ok(value) — whose first argument is a non-trivial, boolean-reducing expression. The rule is enabled at error severity under the existing dd-trace/tests/all config block, so it applies across the TEST_FILES glob (packages/*/test/**, integration-tests/**, and any *.spec.js).

The PR also applies the rule to the entire existing test suite — 716 violations across 232 files were fixed in this branch (mostly via an AST-based codemod that emitted concise, side-effect-safe messages using util.inspect, with a small set of edge cases extracted into named variables by hand).

Motivation

Boolean assertions like assert.ok(duration >= 1000) fail with Expected true, got false — which tells you nothing about the actual value of duration. When that assertion is in a flaky test, you're left guessing whether duration was 500ms or 5ms, making the failure dramatically harder to debug than it needs to be. Forcing a second-argument message nudges authors to surface the runtime value (e.g. assert.ok(duration >= 1000, `Expected ${duration} >= 1000`)), which is what you almost always need when triaging a CI failure.

What the rule flags

An expression is flagged (and so requires a message) when it boolean-reduces, hiding the operand values behind a plain true / false:

  • Value comparisons<, <=, >, >=, ===, !==, ==, !=
  • Logical combinations&&, ||, ??
  • in / instanceof — only when an operand isn't a simple reference; with simple operands the source line already fully describes the question
  • Boolean-returning predicate method callsarr.includes(x), arr.some(cb), arr.every(cb), obj.hasOwnProperty(k), Object.hasOwn(obj, k), Array.isArray(x), Buffer.isBuffer(x), Number.isNaN(x) / isFinite / isInteger / isSafeInteger, Object.isFrozen(x) / isSealed / isExtensible, buf.equals(other)
  • new expressions and other shapes whose value isn't meaningful on its own

String-matching predicates (startsWith / endsWith / String#match / RegExp#test) are intentionally not in this list — the sibling eslint-prefer-assert-match rule handles those with the more specific assert.match / assert.doesNotMatch suggestion and an autofixer.

What's allowed without a message

The rule deliberately allows assertions whose source line is already self-describing, so it doesn't get in the way of idiomatic code. Node's AssertionError prints both the source line and the actual runtime value of the asserted expression, so the following stay informative on failure without an explicit message:

  • Truthy checks of a value, including dynamic indexing — isReady, obj.prop.sub, arr[0], arr[i], map[`key-${id}`], obj?.prop?.sub
  • Calls that may return datagetResult(), arr.find(cb), predicate(x), items.map(transform). Arguments are intentionally not inspected: a complex argument can't make a value-returning call any less informative on failure
  • Getter-style navigation (zero-arg method calls composed with member access) — span.context(), span.context()._tags, arr.entries()
  • Structural unary ops on a trivial operand!x, !!x, typeof x, void x, delete obj.k
  • in / instanceof with trivial operands'foo' in carrier, err instanceof Error, !('x-datadog-trace-id' in carrier)

Autofixer

For value comparisons whose operands are side-effect-free, the rule autofixes by appending a message that interpolates the operands: assert.ok(x > 5) becomes assert.ok(x > 5, `Expected ${x} > 5`). The set of autofixed operators is <, <=, >, >=, ==, !=.

=== and !== are flagged but not autofixed: the better migration is to assert.strictEqual / assert.notStrictEqual (which no-restricted-syntax in the eslint config already nudges users toward), so a mechanical message wrap here would compete with that.

The autofixer also correctly handles parenthesized first arguments — without that, assert.ok((x >= 1)) would be rewritten to assert.ok((x >= 1, `Expected ${x} >= 1`)) (a comma-sequence expression that makes the assertion a no-op). It now walks past balanced surrounding ) tokens before inserting, with regression tests covering the pattern.

Scope of the cleanup

Applying the rule across the test suite produced 716 errors across 232 files. The fixes break down into a few families:

  • Array.isArray(x) / Object.hasOwn(o, k) / Number.isFinite(n) / arr.includes(v) / etc. — message added that interpolates the relevant operand or, for Object.hasOwn, the object's own keys
  • Value comparisons (x > 0, length >= 1, …) — autofixed by the rule itself
  • Logical combinations — message reports the relevant subject expression
  • Side-effecting operands — extracted into a const above the assertion and referenced twice (once in the check, once in the message), so the message can't re-evaluate something side-effectful
  • A handful of cases were rewritten to use assert.notStrictEqual(a, b) (when the original was assert.ok(a !== b)) per the existing no-restricted-syntax nudge

Most fixes use util.inspect to render values; the import was added to ~200 test files (or extended onto an existing node:util destructure where one already existed), grouped with the file's other builtin imports.

@watson watson self-assigned this May 19, 2026

watson commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

@dd-octo-sts

dd-octo-sts Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Overall package size

Self size: 5.84 MB
Deduped: 6.87 MB
No deduping: 6.87 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from 48a5a27 to b8a6087 Compare May 19, 2026 08:48
@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented May 19, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 1 Pipeline job failed

All Green | all-green   View in Datadog   GitHub Actions

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 86.50% (-0.00%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 5c3322e | Docs | Datadog PR Page | Give us feedback!

@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from b8a6087 to 18217ad Compare May 19, 2026 08:58
@pr-commenter

pr-commenter Bot commented May 19, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-05-20 19:49:40

Comparing candidate commit 5c3322e in PR branch watson/eslint-boolean-assert-rule with baseline commit 7caa2c9 in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 1505 metrics, 88 unstable metrics.

@codecov

codecov Bot commented May 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.10%. Comparing base (7caa2c9) to head (5c3322e).

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #8537       +/-   ##
===========================================
- Coverage   89.76%   63.10%   -26.66%     
===========================================
  Files         844      504      -340     
  Lines       45733    32000    -13733     
  Branches     8530     5828     -2702     
===========================================
- Hits        41054    20195    -20859     
- Misses       4679    11805     +7126     
Flag Coverage Δ
aiguard-integration-active ?
aiguard-integration-latest ?
aiguard-integration-maintenance ?
aiguard-macos 34.99% <ø> (-0.09%) ⬇️
aiguard-ubuntu ?
aiguard-windows ?
apm-capabilities-tracing-macos ?
apm-capabilities-tracing-ubuntu-active ?
apm-capabilities-tracing-ubuntu-latest ?
apm-capabilities-tracing-ubuntu-maintenance ?
apm-capabilities-tracing-ubuntu-oldest ?
apm-capabilities-tracing-windows ?
apm-integrations-aerospike-18-gte.5.2.0 ?
apm-integrations-aerospike-20-gte.5.5.0 ?
apm-integrations-aerospike-22-gte.5.12.1 ?
apm-integrations-aerospike-22-gte.6.0.0 ?
apm-integrations-aerospike-eol- ?
apm-integrations-child-process ?
apm-integrations-confluentinc-kafka-javascript-18 ?
apm-integrations-confluentinc-kafka-javascript-20 ?
apm-integrations-confluentinc-kafka-javascript-22 ?
apm-integrations-confluentinc-kafka-javascript-24 ?
apm-integrations-couchbase-18 ?
apm-integrations-couchbase-eol ?
apm-integrations-dns ?
apm-integrations-elasticsearch ?
apm-integrations-http-latest ?
apm-integrations-http-maintenance ?
apm-integrations-http-oldest 42.24% <ø> (-0.08%) ⬇️
apm-integrations-http2 ?
apm-integrations-kafkajs-latest ?
apm-integrations-kafkajs-oldest ?
apm-integrations-net ?
apm-integrations-next-11.1.4 ?
apm-integrations-next-12.3.7 ?
apm-integrations-next-13.0.0 ?
apm-integrations-next-13.2.0 ?
apm-integrations-next-13.5.11 ?
apm-integrations-next-14.0.0 ?
apm-integrations-next-14.2.35 ?
apm-integrations-next-14.2.6 ?
apm-integrations-next-14.2.7 ?
apm-integrations-next-15.0.0 ?
apm-integrations-next-15.4.0 ?
apm-integrations-oracledb ?
apm-integrations-prisma-18-gte.6.16.0.and.lt.7.0.0 ?
apm-integrations-prisma-latest-all ?
apm-integrations-restify ?
apm-integrations-sharedb 34.00% <ø> (-0.09%) ⬇️
apm-integrations-tedious ?
appsec-express ?
appsec-fastify ?
appsec-graphql ?
appsec-integration-active ?
appsec-integration-latest ?
appsec-integration-maintenance ?
appsec-integration-oldest ?
appsec-kafka ?
appsec-ldapjs ?
appsec-lodash ?
appsec-macos ?
appsec-mongodb-core ?
appsec-mongoose ?
appsec-mysql ?
appsec-next-latest-11.1.4 ?
appsec-next-latest-12.3.7 ?
appsec-next-latest-13.0.0 ?
appsec-next-latest-13.2.0 ?
appsec-next-latest-13.5.11 ?
appsec-next-latest-14.0.0 ?
appsec-next-latest-14.2.35 ?
appsec-next-latest-14.2.6 ?
appsec-next-latest-14.2.7 ?
appsec-next-latest-15.0.0 ?
appsec-next-latest-latest ?
appsec-next-oldest-11.1.4 ?
appsec-next-oldest-12.3.7 ?
appsec-next-oldest-13.0.0 ?
appsec-next-oldest-13.2.0 ?
appsec-next-oldest-13.5.11 ?
appsec-next-oldest-14.0.0 ?
appsec-next-oldest-14.2.35 ?
appsec-next-oldest-14.2.6 ?
appsec-next-oldest-14.2.7 ?
appsec-next-oldest-15.0.0 ?
appsec-next-oldest-latest ?
appsec-node-serialize ?
appsec-passport ?
appsec-postgres ?
appsec-sourcing ?
appsec-stripe ?
appsec-template ?
appsec-ubuntu ?
appsec-windows ?
debugger-ubuntu-active ?
debugger-ubuntu-latest ?
debugger-ubuntu-maintenance ?
debugger-ubuntu-oldest ?
instrumentations-instrumentation-bluebird ?
instrumentations-instrumentation-body-parser 37.11% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-child_process ?
instrumentations-instrumentation-cookie-parser ?
instrumentations-instrumentation-express ?
instrumentations-instrumentation-express-mongo-sanitize ?
instrumentations-instrumentation-express-session 36.81% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-fs 29.05% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-generic-pool 28.68% <ø> (ø)
instrumentations-instrumentation-http 36.31% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-knex ?
instrumentations-instrumentation-light-my-request ?
instrumentations-instrumentation-mongoose ?
instrumentations-instrumentation-multer 36.78% <ø> (-0.08%) ⬇️
instrumentations-instrumentation-mysql2 ?
instrumentations-instrumentation-passport ?
instrumentations-instrumentation-passport-http ?
instrumentations-instrumentation-passport-local ?
instrumentations-instrumentation-pg ?
instrumentations-instrumentation-promise 29.30% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-promise-js 29.31% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-q 29.34% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-url 29.26% <ø> (-0.09%) ⬇️
instrumentations-instrumentation-when 29.32% <ø> (-0.09%) ⬇️
instrumentations-integration-esbuild-0.16.12-active ?
instrumentations-integration-esbuild-0.16.12-latest ?
instrumentations-integration-esbuild-0.16.12-maintenance ?
instrumentations-integration-esbuild-0.16.12-oldest ?
instrumentations-integration-esbuild-latest-active ?
instrumentations-integration-esbuild-latest-latest ?
instrumentations-integration-esbuild-latest-maintenance ?
instrumentations-integration-esbuild-latest-oldest ?
llmobs-ai ?
llmobs-anthropic ?
llmobs-bedrock ?
llmobs-google-genai ?
llmobs-langchain ?
llmobs-openai-latest ?
llmobs-openai-oldest ?
llmobs-sdk-active ?
llmobs-sdk-latest ?
llmobs-sdk-maintenance ?
llmobs-sdk-oldest ?
llmobs-vertex-ai ?
master-coverage 63.10% <ø> (?)
openfeature-macos 38.02% <ø> (-0.06%) ⬇️
openfeature-ubuntu ?
openfeature-unit-active 49.27% <ø> (ø)
openfeature-unit-latest 49.11% <ø> (ø)
openfeature-unit-maintenance 49.27% <ø> (ø)
openfeature-unit-oldest 49.27% <ø> (ø)
openfeature-windows ?
platform-core 36.45% <ø> (ø)
platform-esbuild 39.82% <ø> (ø)
platform-instrumentations-misc ?
platform-integration-active ?
platform-integration-latest ?
platform-integration-maintenance ?
platform-integration-oldest ?
platform-shimmer ?
platform-unit-guardrails 35.42% <ø> (ø)
platform-webpack 20.36% <ø> (ø)
plugins-azure-event-hubs ?
plugins-azure-service-bus ?
plugins-bullmq ?
plugins-cassandra ?
plugins-cookie ?
plugins-cookie-parser 27.14% <ø> (ø)
plugins-crypto 27.27% <ø> (ø)
plugins-dd-trace-api 34.72% <ø> (-0.09%) ⬇️
plugins-express-mongo-sanitize ?
plugins-express-session ?
plugins-fastify ?
plugins-fetch 35.18% <ø> (-0.08%) ⬇️
plugins-fs ?
plugins-generic-pool ?
plugins-google-cloud-pubsub ?
plugins-grpc ?
plugins-handlebars ?
plugins-hapi ?
plugins-hono ?
plugins-ioredis ?
plugins-knex ?
plugins-langgraph 34.56% <ø> (-0.09%) ⬇️
plugins-ldapjs ?
plugins-light-my-request ?
plugins-limitd-client ?
plugins-lodash 26.05% <ø> (ø)
plugins-mariadb ?
plugins-memcached ?
plugins-microgateway-core ?
plugins-modelcontextprotocol-sdk ?
plugins-moleculer ?
plugins-mongodb ?
plugins-mongodb-core ?
plugins-mongoose ?
plugins-multer ?
plugins-mysql ?
plugins-mysql2 ?
plugins-node-serialize 27.47% <ø> (ø)
plugins-opensearch ?
plugins-passport-http ?
plugins-pino ?
plugins-postgres ?
plugins-process 27.27% <ø> (ø)
plugins-pug ?
plugins-redis ?
plugins-router ?
plugins-sequelize ?
plugins-test-and-upstream-amqp10 ?
plugins-test-and-upstream-amqplib ?
plugins-test-and-upstream-apollo ?
plugins-test-and-upstream-avsc 35.28% <ø> (-0.09%) ⬇️
plugins-test-and-upstream-bunyan ?
plugins-test-and-upstream-connect ?
plugins-test-and-upstream-graphql ?
plugins-test-and-upstream-koa ?
plugins-test-and-upstream-protobufjs 35.49% <ø> (-0.09%) ⬇️
plugins-test-and-upstream-rhea ?
plugins-undici ?
plugins-url ?
plugins-valkey ?
plugins-vm ?
plugins-winston ?
plugins-ws 38.26% <ø> (-0.08%) ⬇️
profiling-macos ?
profiling-ubuntu ?
profiling-windows ?
serverless-aws-sdk-latest-aws-sdk ?
serverless-aws-sdk-latest-bedrockruntime ?
serverless-aws-sdk-latest-client ?
serverless-aws-sdk-latest-dynamodb ?
serverless-aws-sdk-latest-eventbridge ?
serverless-aws-sdk-latest-kinesis ?
serverless-aws-sdk-latest-lambda ?
serverless-aws-sdk-latest-s3 ?
serverless-aws-sdk-latest-serverless-peer-service ?
serverless-aws-sdk-latest-sns ?
serverless-aws-sdk-latest-sqs ?
serverless-aws-sdk-latest-stepfunctions ?
serverless-aws-sdk-latest-util ?
serverless-aws-sdk-oldest-aws-sdk ?
serverless-aws-sdk-oldest-bedrockruntime ?
serverless-aws-sdk-oldest-client ?
serverless-aws-sdk-oldest-dynamodb ?
serverless-aws-sdk-oldest-eventbridge ?
serverless-aws-sdk-oldest-kinesis ?
serverless-aws-sdk-oldest-lambda ?
serverless-aws-sdk-oldest-s3 ?
serverless-aws-sdk-oldest-serverless-peer-service ?
serverless-aws-sdk-oldest-sns ?
serverless-aws-sdk-oldest-sqs ?
serverless-aws-sdk-oldest-stepfunctions ?
serverless-aws-sdk-oldest-util ?
serverless-azure-durable-functions ?
serverless-azure-functions-eventhubs ?
serverless-azure-functions-servicebus ?
serverless-lambda ?
test-optimization-cucumber-latest-7.0.0 50.32% <ø> (+0.01%) ⬆️
test-optimization-cucumber-latest-latest 53.20% <ø> (+0.12%) ⬆️
test-optimization-cucumber-oldest-7.0.0 50.36% <ø> (+0.12%) ⬆️
test-optimization-cypress-latest-12.0.0-commonJS 48.80% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-12.0.0-esm 48.83% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-14.5.4-commonJS 48.65% <ø> (-0.04%) ⬇️
test-optimization-cypress-latest-14.5.4-esm 48.68% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-latest-commonJS 49.14% <ø> (+0.07%) ⬆️
test-optimization-cypress-latest-latest-esm 49.17% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-12.0.0-commonJS 48.84% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-12.0.0-esm 48.87% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-14.5.4-commonJS 48.68% <ø> (+0.07%) ⬆️
test-optimization-cypress-oldest-14.5.4-esm 48.72% <ø> (+0.07%) ⬆️
test-optimization-jest-latest-latest 54.83% <ø> (+0.08%) ⬆️
test-optimization-jest-latest-oldest 53.65% <ø> (+0.08%) ⬆️
test-optimization-jest-oldest-latest 54.83% <ø> (+0.08%) ⬆️
test-optimization-jest-oldest-oldest 53.59% <ø> (+0.08%) ⬆️
test-optimization-mocha-latest-latest 53.63% <ø> (+0.08%) ⬆️
test-optimization-mocha-latest-oldest 51.29% <ø> (+0.08%) ⬆️
test-optimization-mocha-oldest-latest 53.70% <ø> (+0.08%) ⬆️
test-optimization-mocha-oldest-oldest 51.23% <ø> (+0.06%) ⬆️
test-optimization-playwright-latest-latest-playwright-active-test-span 44.35% <ø> (+0.28%) ⬆️
test-optimization-playwright-latest-latest-playwright-atr 43.13% <ø> (+0.11%) ⬆️
test-optimization-playwright-latest-latest-playwright-efd 43.55% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-latest-playwright-final-status 43.61% <ø> (+0.13%) ⬆️
test-optimization-playwright-latest-latest-playwright-impacted-tests 43.06% <ø> (ø)
test-optimization-playwright-latest-latest-playwright-reporting 43.02% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-latest-playwright-test-management 44.79% <ø> (+0.10%) ⬆️
test-optimization-playwright-latest-oldest-playwright-active-test-span 44.42% <ø> (+0.28%) ⬆️
test-optimization-playwright-latest-oldest-playwright-atr 43.34% <ø> (+0.11%) ⬆️
test-optimization-playwright-latest-oldest-playwright-efd 43.61% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-oldest-playwright-final-status 43.67% <ø> (+0.11%) ⬆️
test-optimization-playwright-latest-oldest-playwright-impacted-tests 43.11% <ø> (ø)
test-optimization-playwright-latest-oldest-playwright-reporting 43.09% <ø> (+0.09%) ⬆️
test-optimization-playwright-latest-oldest-playwright-test-management 44.86% <ø> (+0.10%) ⬆️
test-optimization-playwright-oldest-latest-playwright-active-test-span 44.39% <ø> (+0.28%) ⬆️
test-optimization-playwright-oldest-latest-playwright-atr 43.17% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-latest-playwright-efd 43.57% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-latest-playwright-final-status 43.62% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-latest-playwright-impacted-tests 43.10% <ø> (ø)
test-optimization-playwright-oldest-latest-playwright-reporting 43.03% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-latest-playwright-test-management 44.80% <ø> (+0.10%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-active-test-span 44.46% <ø> (+0.28%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-atr 43.38% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-efd 43.62% <ø> (+0.09%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-final-status 43.68% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-impacted-tests 43.15% <ø> (ø)
test-optimization-playwright-oldest-oldest-playwright-reporting 43.13% <ø> (+0.11%) ⬆️
test-optimization-playwright-oldest-oldest-playwright-test-management 44.88% <ø> (+0.10%) ⬆️
test-optimization-selenium-latest 45.57% <ø> (+0.29%) ⬆️
test-optimization-selenium-oldest 45.37% <ø> (+0.30%) ⬆️
test-optimization-testopt-active 46.96% <ø> (+0.13%) ⬆️
test-optimization-testopt-latest 46.92% <ø> (+0.13%) ⬆️
test-optimization-testopt-maintenance 46.96% <ø> (+0.13%) ⬆️
test-optimization-testopt-oldest 47.84% <ø> (+0.14%) ⬆️
test-optimization-vitest-latest 51.22% <ø> (+0.10%) ⬆️
test-optimization-vitest-oldest 48.31% <ø> (+0.33%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@watson watson changed the base branch from master to graphite-base/8537 May 19, 2026 09:48
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from 18217ad to 30bc86a Compare May 19, 2026 09:48
@watson watson changed the base branch from graphite-base/8537 to watson/eslint-equal-assert May 19, 2026 09:48
@watson watson force-pushed the watson/eslint-equal-assert branch from f0d9d5c to eddfeab Compare May 19, 2026 09:53
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from 30bc86a to ca8199d Compare May 19, 2026 09:53
Base automatically changed from watson/eslint-equal-assert to master May 19, 2026 10:17
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from ca8199d to b220b28 Compare May 19, 2026 10:22
@watson watson changed the base branch from master to graphite-base/8537 May 19, 2026 12:09
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from b220b28 to 02d15e5 Compare May 19, 2026 12:09
@watson watson changed the base branch from graphite-base/8537 to watson/eslint-rule-prefer-match May 19, 2026 12:09
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from 02d15e5 to f2ac003 Compare May 19, 2026 12:20
Base automatically changed from watson/eslint-rule-prefer-match to master May 19, 2026 12:34
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch 3 times, most recently from 941aa34 to d24554d Compare May 19, 2026 13:16
watson added 3 commits May 20, 2026 13:23
Add a custom ESLint rule that flags `assert(...)` / `assert.ok(...)`
calls whose first argument is a non-trivial expression and no second
message argument is provided. Without a message, failures only report
"Expected true, got false", hiding the actual value being asserted on —
debugging a flaky `assert.ok(duration >= 1000)` is painful when you
can't tell if `duration` was 500ms or 5ms.

Self-describing shapes are still allowed without a message: bare
references (`isReady`, `obj.prop`), structural unary ops (`!x`,
`typeof x`, `delete obj.k`), `in` / `instanceof` with trivial operands,
predicate-style calls (`arr.includes('foo')`, `Array.isArray(x)`), and
zero-arg method-chain calls used as getter-style navigation
(`span.context()._tags`).

Scoped to test files via the existing `TEST_FILES` glob.
@watson watson force-pushed the watson/eslint-boolean-assert-rule branch from d24554d to 3967cf5 Compare May 20, 2026 11:27
@watson watson requested review from khanayan123, leoromanovsky, sameerank and tlhunter and removed request for a team May 20, 2026 14:23
@watson watson changed the title chore(eslint): require messages on boolean test assertions chore(eslint): require descriptive messages on boolean test assertions May 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce0e0ced6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +262 to +263
const lhsPart = firstArg.left.type === 'Literal' ? lhsText : '${' + lhsText + '}'
const rhsPart = firstArg.right.type === 'Literal' ? rhsText : '${' + rhsText + '}'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Guard template-literal autofixes against ${ literals

When eslint --fix sees a comparison against a literal string containing ${...} (for example assert.ok(value == '${expected}')), these lines copy the literal source directly into the generated template-literal message, so the fixed code becomes a message that interpolates expected instead of showing the literal text and can even throw a ReferenceError before assert.ok runs. Please bail out or escape template-literal syntax for literal operands before returning a fix.

Useful? React with 👍 / 👎.

@BridgeAR BridgeAR left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, while I do not have a strong opinion. It will be nicer to read, while it probably does not make a big difference 🤷

@watson watson enabled auto-merge (squash) May 20, 2026 14:35
@watson watson merged commit 600610b into master May 21, 2026
2900 of 3897 checks passed
@watson watson deleted the watson/eslint-boolean-assert-rule branch May 21, 2026 08:20
BridgeAR pushed a commit that referenced this pull request May 25, 2026
For literal operands, `buildAutofixMessage` embeds the source text
verbatim into the synthesised template's static segments. When that
text contains `${...}`, it turns into a real interpolation —
silently changing the message, or throwing `ReferenceError` if the
identifier isn't in scope before `assert.ok` even runs.

Bail out (return null) in that case rather than try to escape, and
drop the now-obsolete comment about backslashes — the broader
literal check supersedes it. Includes regression tests for `==`,
`>`, and the escaped `\${...}` variant.

Follow-up to #8537.
This was referenced May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants