From e1d1e7ef3086d525f8a37ec708441de52a41e9c9 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 17 Sep 2025 14:43:58 -0700 Subject: [PATCH 1/6] Add a `StrippedLocation` interface and pipe it through the CommentEnhancers. --- browser-extension/src/lib/enhancer.ts | 11 +++++++++- .../lib/enhancers/CommentEnhancerMissing.tsx | 4 ++-- .../github/githubIssueAddComment.tsx | 17 +++++++++------- .../github/githubIssueNewComment.tsx | 17 +++++++++------- .../enhancers/github/githubPRAddComment.tsx | 20 +++++++++---------- .../enhancers/github/githubPRNewComment.tsx | 17 +++++++++------- 6 files changed, 52 insertions(+), 34 deletions(-) diff --git a/browser-extension/src/lib/enhancer.ts b/browser-extension/src/lib/enhancer.ts index 5c9e95b..168bcf5 100644 --- a/browser-extension/src/lib/enhancer.ts +++ b/browser-extension/src/lib/enhancer.ts @@ -19,6 +19,15 @@ export interface CommentEvent { draft?: string } +/** + * Minimal location information that enhancers need for routing decisions. + * Avoids dependency on global window/location objects for better testability. + */ +export interface StrippedLocation { + domain: string + pathname: string +} + /** Wraps the textareas of a given platform with Gitcasso's enhancements. */ export interface CommentEnhancer { /** Guarantees to only return a type within this list. */ @@ -27,7 +36,7 @@ export interface CommentEnhancer { * Whenever a new `textarea` is added to any webpage, this method is called. * If we return non-null, then we become the handler for that text area. */ - tryToEnhance(textarea: HTMLTextAreaElement): Spot | null + tryToEnhance(textarea: HTMLTextAreaElement, location: StrippedLocation): Spot | null /** This gets called the first time that `tryToEnhance` returns non-null. */ prepareForFirstEnhancement(): void /** diff --git a/browser-extension/src/lib/enhancers/CommentEnhancerMissing.tsx b/browser-extension/src/lib/enhancers/CommentEnhancerMissing.tsx index a470feb..f59a6e6 100644 --- a/browser-extension/src/lib/enhancers/CommentEnhancerMissing.tsx +++ b/browser-extension/src/lib/enhancers/CommentEnhancerMissing.tsx @@ -1,6 +1,6 @@ import type { OverTypeInstance } from 'overtype' import type { ReactNode } from 'react' -import type { CommentEnhancer, CommentSpot } from '../enhancer' +import type { CommentEnhancer, CommentSpot, StrippedLocation } from '../enhancer' /** Used when an entry is in the table which we don't recognize. */ export class CommentEnhancerMissing implements CommentEnhancer { @@ -40,7 +40,7 @@ export class CommentEnhancerMissing implements CommentEnhancer { forSpotTypes(): string[] { throw new Error('Method not implemented.') } - tryToEnhance(_textarea: HTMLTextAreaElement): CommentSpot | null { + tryToEnhance(_textarea: HTMLTextAreaElement, _location: StrippedLocation): CommentSpot | null { throw new Error('Method not implemented.') } prepareForFirstEnhancement(): void { diff --git a/browser-extension/src/lib/enhancers/github/githubIssueAddComment.tsx b/browser-extension/src/lib/enhancers/github/githubIssueAddComment.tsx index e3b195d..edf7671 100644 --- a/browser-extension/src/lib/enhancers/github/githubIssueAddComment.tsx +++ b/browser-extension/src/lib/enhancers/github/githubIssueAddComment.tsx @@ -1,7 +1,7 @@ import { IssueOpenedIcon } from '@primer/octicons-react' import OverType, { type OverTypeInstance } from 'overtype' import type React from 'react' -import type { CommentEnhancer, CommentSpot } from '@/lib/enhancer' +import type { CommentEnhancer, CommentSpot, StrippedLocation } from '@/lib/enhancer' import { logger } from '@/lib/logger' import { modifyDOM } from '../modifyDOM' import { commonGithubOptions } from './ghOptions' @@ -20,19 +20,22 @@ export class GitHubIssueAddCommentEnhancer implements CommentEnhancer Date: Wed, 17 Sep 2025 14:56:02 -0700 Subject: [PATCH 2/6] Pipe it into tests and prod. --- browser-extension/src/entrypoints/content.ts | 11 +++++++++-- browser-extension/src/lib/registries.ts | 6 +++--- .../tests/lib/enhancers/github.test.ts | 17 +++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/browser-extension/src/entrypoints/content.ts b/browser-extension/src/entrypoints/content.ts index b49267f..04ed1cc 100644 --- a/browser-extension/src/entrypoints/content.ts +++ b/browser-extension/src/entrypoints/content.ts @@ -1,5 +1,5 @@ import { CONFIG } from '../lib/config' -import type { CommentEvent, CommentSpot } from '../lib/enhancer' +import type { CommentEvent, CommentSpot, StrippedLocation } from '../lib/enhancer' import { logger } from '../lib/logger' import { EnhancerRegistry, TextareaRegistry } from '../lib/registries' @@ -9,6 +9,13 @@ const enhancedTextareas = new TextareaRegistry() // Expose for debugging in har:view ;(window as any).gitcassoTextareaRegistry = enhancedTextareas +function detectLocation(): StrippedLocation { + return { + domain: window.location.host, + pathname: window.location.pathname, + } +} + function sendEventToBackground(type: 'ENHANCED' | 'DESTROYED', spot: CommentSpot): void { const message: CommentEvent = { spot, @@ -89,7 +96,7 @@ function enhanceMaybe(textarea: HTMLTextAreaElement) { injectStyles() try { - const enhancedTextarea = enhancers.tryToEnhance(textarea) + const enhancedTextarea = enhancers.tryToEnhance(textarea, detectLocation()) if (enhancedTextarea) { logger.debug( 'Identified textarea:', diff --git a/browser-extension/src/lib/registries.ts b/browser-extension/src/lib/registries.ts index 2c7cc07..35081e2 100644 --- a/browser-extension/src/lib/registries.ts +++ b/browser-extension/src/lib/registries.ts @@ -1,6 +1,6 @@ import type { OverTypeInstance } from 'overtype' import OverType from 'overtype' -import type { CommentEnhancer, CommentSpot } from './enhancer' +import type { CommentEnhancer, CommentSpot, StrippedLocation } from './enhancer' import { CommentEnhancerMissing } from './enhancers/CommentEnhancerMissing' import { GitHubIssueAddCommentEnhancer } from './enhancers/github/githubIssueAddComment' import { GitHubIssueNewCommentEnhancer } from './enhancers/github/githubIssueNewComment' @@ -59,10 +59,10 @@ export class EnhancerRegistry { return (this.byType.get(spot.type) || new CommentEnhancerMissing()) as CommentEnhancer } - tryToEnhance(textarea: HTMLTextAreaElement): EnhancedTextarea | null { + tryToEnhance(textarea: HTMLTextAreaElement, location: StrippedLocation): EnhancedTextarea | null { for (const enhancer of this.enhancers) { try { - const spot = enhancer.tryToEnhance(textarea) + const spot = enhancer.tryToEnhance(textarea, location) if (spot) { // Prepare enhancer on first use if (!this.preparedEnhancers.has(enhancer)) { diff --git a/browser-extension/tests/lib/enhancers/github.test.ts b/browser-extension/tests/lib/enhancers/github.test.ts index 587be2f..50a3750 100644 --- a/browser-extension/tests/lib/enhancers/github.test.ts +++ b/browser-extension/tests/lib/enhancers/github.test.ts @@ -3,14 +3,19 @@ import { describe, expect, usingHar } from '../../har-fixture' // must import fixture **first** for mocks, the `expect` keeps biome from changing sort-order expect +import type { StrippedLocation } from '@/lib/enhancer' import { EnhancerRegistry } from '../../../src/lib/registries' const enhancers = new EnhancerRegistry() -function enhancements(document: Document) { +function enhancements(document: Document, window: Window) { const textareas = document.querySelectorAll('textarea') + const location: StrippedLocation = { + domain: window.location.host, + pathname: window.location.pathname, + } const spotsFound = [] for (const textarea of textareas) { - const enhanced = enhancers.tryToEnhance(textarea) + const enhanced = enhancers.tryToEnhance(textarea, location) const forValue = `id=${textarea.id} name=${textarea.name} className=${textarea.className}` if (enhanced) { spotsFound.push({ @@ -31,7 +36,7 @@ function enhancements(document: Document) { describe('github', () => { usingHar('gh_pr').it('should create the correct spot object', async () => { - expect(enhancements(document)).toMatchInlineSnapshot(` + expect(enhancements(document, window)).toMatchInlineSnapshot(` [ { "for": "id=feedback name=feedback className=form-control width-full mb-2", @@ -66,7 +71,7 @@ describe('github', () => { `) }) usingHar('gh_new_pr').it('should create the correct spot object', async () => { - expect(enhancements(document)).toMatchInlineSnapshot(` + expect(enhancements(document, window)).toMatchInlineSnapshot(` [ { "for": "id=feedback name=feedback className=form-control width-full mb-2", @@ -98,7 +103,7 @@ describe('github', () => { `) }) usingHar('gh_issue').it('should create the correct spot object', async () => { - expect(enhancements(document)).toMatchInlineSnapshot(` + expect(enhancements(document, window)).toMatchInlineSnapshot(` [ { "for": "id=feedback name=feedback className=form-control width-full mb-2", @@ -108,7 +113,7 @@ describe('github', () => { `) }) usingHar('gh_new_issue').it('should create the correct spot object', async () => { - expect(enhancements(document)).toMatchInlineSnapshot(` + expect(enhancements(document, window)).toMatchInlineSnapshot(` [ { "for": "id=feedback name=feedback className=form-control width-full mb-2 overtype-input", From 6d5d0a94d783a81e14fa9f2aa51113f68a085409 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 17 Sep 2025 15:06:31 -0700 Subject: [PATCH 3/6] Modify har-view to match. --- browser-extension/tests/har-view.ts | 35 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/browser-extension/tests/har-view.ts b/browser-extension/tests/har-view.ts index 80cbba9..b19999f 100644 --- a/browser-extension/tests/har-view.ts +++ b/browser-extension/tests/har-view.ts @@ -315,31 +315,31 @@ function injectGitcassoScript(key: keyof typeof PAGES, html: string) { const contentScriptTag = `