Skip to content

Added regression test pinning IndexNow ping URL output#27711

Merged
allouis merged 1 commit into
mainfrom
hkg-1738-test-indexnow-url
May 7, 2026
Merged

Added regression test pinning IndexNow ping URL output#27711
allouis merged 1 commit into
mainfrom
hkg-1738-test-indexnow-url

Conversation

@allouis
Copy link
Copy Markdown
Collaborator

@allouis allouis commented May 6, 2026

Summary

Adds a unit test pinning the IndexNow ping URL output. Stubs request(), drives indexnowListener against a fake post with an SEO-relevant change, and asserts the ping URL exactly matches the URL service's return value for that post.

Why

We're about to migrate IndexNow's URL-service lookup from getUrlByResourceId(post.id) to facade.getUrlForResource(post). The existing test only stubs the URL service as a sanity check and never asserts on the URL the request body actually carries. Before the migration, we want a regression test pinning the ping URL through the public listener.

This test lands on top of main and is independently mergeable — no production change.

Stacked on #27710 because the broader refactor that follows modifies test files introduced by both PRs. Once #27710 merges, this PR's diff stays at 1 commit and its base auto-updates to main.

ref https://linear.app/ghost/issue/HKG-1767/

Test plan

  • New test passes
  • No production code changes

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Review Change Stack

Walkthrough

This pull request adds a test case to the IndexNow service test suite that validates the ping() method constructs the correct URL query parameter. The test imports urlService, stubs its getUrlByResourceId method to return a fixed URL, stubs the internal request function, invokes ping() with the IndexNow API key configured, and asserts that the request URL contains the expected url query parameter value matching the stubbed resource URL.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a regression test that pins the IndexNow ping URL output.
Description check ✅ Passed The description provides comprehensive context about the test addition, its purpose as a regression safeguard, and the upcoming refactor it protects against.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hkg-1738-test-indexnow-url

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
ghost/core/test/unit/server/services/indexnow.test.js (1)

419-420: ⚡ Quick win

Avoid coupling this regression to one internal URL API.

This suite is framed as output pinning, but stubbing only getUrlByResourceId makes it fail on call-shape refactors even when ?url= output remains correct. Stub both URL entry points so the test stays behavior-focused.

Suggested adjustment
         beforeEach(function () {
             sinon.stub(urlService, 'getUrlByResourceId').returns(POST_URL);
+            sinon.stub(urlService.facade, 'getUrlForResource').returns(POST_URL);
 
             requestStub = sinon.stub().resolves({statusCode: 200});
             resetIndexNow = indexnow.__set__('request', requestStub);
🤖 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 `@ghost/core/test/unit/server/services/indexnow.test.js` around lines 419 -
420, The test currently stubs only urlService.getUrlByResourceId which couples
the spec to that internal API; update the test to stub both public URL entry
points (urlService.getUrlByResourceId and urlService.getUrlByResource) to return
POST_URL so the assertion relies on the external ?url= behavior rather than a
single internal method shape change.
🤖 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.

Nitpick comments:
In `@ghost/core/test/unit/server/services/indexnow.test.js`:
- Around line 419-420: The test currently stubs only
urlService.getUrlByResourceId which couples the spec to that internal API;
update the test to stub both public URL entry points
(urlService.getUrlByResourceId and urlService.getUrlByResource) to return
POST_URL so the assertion relies on the external ?url= behavior rather than a
single internal method shape change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3fc08892-e36a-4a11-a561-d83565dab991

📥 Commits

Reviewing files that changed from the base of the PR and between b2e7082 and 2162eca.

📒 Files selected for processing (28)
  • ghost/core/core/boot.js
  • ghost/core/core/bridge.js
  • ghost/core/core/frontend/helpers/authors.js
  • ghost/core/core/frontend/helpers/tags.js
  • ghost/core/core/frontend/meta/author-url.js
  • ghost/core/core/frontend/meta/url.js
  • ghost/core/core/frontend/services/routing/controllers/collection.js
  • ghost/core/core/frontend/services/routing/controllers/email-post.js
  • ghost/core/core/frontend/services/routing/controllers/previews.js
  • ghost/core/core/frontend/services/routing/router-manager.js
  • ghost/core/core/frontend/services/rss/generate-feed.js
  • ghost/core/core/server/api/endpoints/utils/serializers/output/utils/url.js
  • ghost/core/core/server/services/audience-feedback/audience-feedback-service.js
  • ghost/core/core/server/services/comments/comments-service-emails.js
  • ghost/core/core/server/services/email-service/email-renderer.js
  • ghost/core/core/server/services/url/index.js
  • ghost/core/core/server/services/url/url-service-facade.ts
  • ghost/core/test/unit/api/canary/utils/serializers/output/utils/url.test.js
  • ghost/core/test/unit/frontend/helpers/authors.test.js
  • ghost/core/test/unit/frontend/helpers/tags.test.js
  • ghost/core/test/unit/frontend/meta/author-url.test.js
  • ghost/core/test/unit/frontend/meta/url.test.js
  • ghost/core/test/unit/frontend/services/routing/controllers/collection.test.js
  • ghost/core/test/unit/frontend/services/rss/generate-feed.test.js
  • ghost/core/test/unit/server/services/audience-feedback/audience-feedback-service.test.js
  • ghost/core/test/unit/server/services/comments/comments-service-emails.test.js
  • ghost/core/test/unit/server/services/indexnow.test.js
  • ghost/core/test/unit/server/services/url/url-service-facade.test.js

@allouis allouis force-pushed the hkg-1738-test-indexnow-url branch from 2162eca to e213b15 Compare May 6, 2026 16:58
@allouis allouis changed the base branch from main to hkg-1738-test-comments-url May 6, 2026 16:59
@allouis allouis force-pushed the hkg-1738-test-comments-url branch from 48cff0d to 83b184a Compare May 7, 2026 07:53
@allouis allouis force-pushed the hkg-1738-test-indexnow-url branch 2 times, most recently from 7f43104 to cdde506 Compare May 7, 2026 07:55
@allouis allouis force-pushed the hkg-1738-test-comments-url branch from 83b184a to 95acc5e Compare May 7, 2026 07:55
Base automatically changed from hkg-1738-test-comments-url to main May 7, 2026 08:58
ref https://linear.app/ghost/issue/HKG-1767/

The IndexNow listener pings a URL derived from the URL service whenever
a post's SEO-relevant fields change. The existing test stubs the URL
service as a sanity check but never asserts on the URL that the request
body actually carries, so a regression in how the listener resolves the
post's URL would slip through. Driving indexnowListener end-to-end and
pinning the ping URL through the public boundary closes that gap.
@allouis allouis force-pushed the hkg-1738-test-indexnow-url branch from cdde506 to aaa0d82 Compare May 7, 2026 09:02
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@ghost/core/test/unit/server/services/indexnow.test.js`:
- Around line 419-438: The test currently stubs urlService.getUrlByResourceId
unconditionally so it returns POST_URL for any arg; change the setup and
assertion so the test verifies the lookup call shape: when calling ping(post)
ensure urlService.getUrlByResourceId is stubbed for the expected id (e.g., use
sinon.stub(urlService, 'getUrlByResourceId').withArgs(post.id).returns(POST_URL)
or alternatively keep the stub but assert the call) and add an assertion like
sinon.assert.calledOnceWith(urlService.getUrlByResourceId, post.id) after await
ping(post) to guarantee the function was invoked with post.id.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b1651e2c-297d-4ffb-9a52-30a636f314a1

📥 Commits

Reviewing files that changed from the base of the PR and between e213b15 and aaa0d82.

📒 Files selected for processing (1)
  • ghost/core/test/unit/server/services/indexnow.test.js

Comment on lines +419 to +438
sinon.stub(urlService, 'getUrlByResourceId').returns(POST_URL);

requestStub = sinon.stub().resolves({statusCode: 200});
resetIndexNow = indexnow.__set__('request', requestStub);

settingsCacheStub.withArgs('indexnow_api_key').returns('a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4');
});

afterEach(function () {
resetIndexNow();
});

it('passes the post URL into the IndexNow request', async function () {
const post = {id: 'abc', slug: 'some-post', type: 'post'};

await ping(post);

sinon.assert.calledOnce(requestStub);
const indexNowUrl = new URL(requestStub.firstCall.args[0]);
assert.equal(indexNowUrl.searchParams.get('url'), POST_URL);
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 | 🟡 Minor | ⚡ Quick win

The getUrlByResourceId stub is unconditional — the test's core regression scenario isn't actually pinned.

The PR's stated goal is to catch a future change that swaps getUrlByResourceId(post.id) for a different call shape (e.g., getUrlForResource(post)). However, the stub at line 419 has no withArgs constraint, so it returns POST_URL regardless of what argument is passed. The final assertion only checks that the URL value in the request matches POST_URL — it does not verify how that URL was looked up.

If ping() were accidentally changed to call getUrlByResourceId(post.url) or getUrlByResourceId(undefined), the stub would still resolve to POST_URL and the test would still pass, silently missing exactly the regression it was designed to catch.

Adding calledOnceWith(post.id) on the urlService.getUrlByResourceId spy is the minimal fix:

🔧 Proposed fix
         sinon.assert.calledOnce(requestStub);
+        sinon.assert.calledOnceWith(urlService.getUrlByResourceId, 'abc');
         const indexNowUrl = new URL(requestStub.firstCall.args[0]);
         assert.equal(indexNowUrl.searchParams.get('url'), POST_URL);
🤖 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 `@ghost/core/test/unit/server/services/indexnow.test.js` around lines 419 -
438, The test currently stubs urlService.getUrlByResourceId unconditionally so
it returns POST_URL for any arg; change the setup and assertion so the test
verifies the lookup call shape: when calling ping(post) ensure
urlService.getUrlByResourceId is stubbed for the expected id (e.g., use
sinon.stub(urlService, 'getUrlByResourceId').withArgs(post.id).returns(POST_URL)
or alternatively keep the stub but assert the call) and add an assertion like
sinon.assert.calledOnceWith(urlService.getUrlByResourceId, post.id) after await
ping(post) to guarantee the function was invoked with post.id.

@allouis allouis merged commit 8e80d1b into main May 7, 2026
43 checks passed
@allouis allouis deleted the hkg-1738-test-indexnow-url branch May 7, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant