@@ -35,15 +35,15 @@ def test_no_proxy_links_editor_to_https_listing_no_get_extension(self):
3535 out = bc .build_cta ("" , "o" , "r" , "1" , repo_with (".cursor" ), issues = 3 )
3636 self .assertIn ("3 architecture issues found" , out )
3737 # Cursor -> Open VSX https listing. A cursor: scheme would be stripped by GitHub.
38- self .assertIn ("[**Open in Cursor β **](https://open-vsx.org/extension/CodeBoarding/codeboarding)" , out )
38+ self .assertIn ("[**Cursor**](https://open-vsx.org/extension/CodeBoarding/codeboarding)" , out )
3939 self .assertNotIn ("cursor:extension" , out )
4040 self .assertNotIn ("Get the extension" , out ) # dropped without a proxy
41- self .assertNotIn ("Open in VS Code" , out ) # cursor-only repo
41+ self .assertNotIn ("VS Code" , out ) # cursor-only repo
4242
4343 def test_no_proxy_vscode_marketplace_https_no_banner_at_zero (self ):
4444 out = bc .build_cta ("" , "o" , "r" , "1" , repo_with ()) # neither dir, no issues
4545 self .assertIn (
46- "[**Open in VS Code β **](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding)" ,
46+ "[**VS Code**](https://marketplace.visualstudio.com/items?itemName=Codeboarding.codeboarding)" ,
4747 out ,
4848 )
4949 self .assertNotIn ("vscode:extension" , out ) # custom scheme stripped by GitHub
@@ -53,22 +53,21 @@ def test_no_proxy_vscode_marketplace_https_no_banner_at_zero(self):
5353 def test_links_banner_and_cursor_only (self ):
5454 out = bc .build_cta ("https://x.dev/" , "Org" , "Repo" , "9" , repo_with (".cursor" ), issues = 2 )
5555 self .assertIn ("2 architecture issues found" , out )
56- self .assertNotIn ("use-workspace" , out ) # webview/browser tier deferred β extension-direct
5756 self .assertIn ("open-in-editor?owner=Org&repo=Repo&pr=9&editor=cursor" , out )
58- self .assertIn ("use-marketplace?owner=Org&repo=Repo&pr=9" , out )
59- self .assertNotIn ("Open in VS Code" , out ) # cursor-only repo
57+ self .assertIn ("use-marketplace?owner=Org&repo=Repo&pr=9" , out ) # proxy "Get the extension"
58+ self .assertNotIn ("VS Code" , out ) # cursor-only repo
6059
6160 def test_no_banner_when_zero_issues_and_default_vscode (self ):
6261 out = bc .build_cta ("https://x.dev" , "o" , "r" , "1" , repo_with (), issues = 0 )
6362 self .assertNotIn ("architecture issue" , out )
64- self .assertIn ("Open in VS Code" , out )
65- self .assertNotIn ("Open in Cursor" , out )
63+ self .assertIn ("VS Code" , out )
64+ self .assertNotIn ("Cursor" , out )
6665
6766 def test_both_editors_singular_issue (self ):
6867 out = bc .build_cta ("https://x.dev" , "o" , "r" , "1" , repo_with (".vscode" , ".cursor" ), issues = 1 )
6968 self .assertIn ("1 architecture issue found" , out ) # singular
70- self .assertIn ("Open in VS Code" , out )
71- self .assertIn ("Open in Cursor" , out )
69+ self .assertIn ("VS Code" , out )
70+ self .assertIn ("Cursor" , out )
7271
7372 def test_trailing_slash_in_base_is_normalized (self ):
7473 a = bc .build_cta ("https://x.dev/" , "o" , "r" , "1" , repo_with ())
@@ -77,26 +76,27 @@ def test_trailing_slash_in_base_is_normalized(self):
7776 self .assertEqual (a , b )
7877
7978
80- class TestWebviewLink (unittest .TestCase ):
79+ class TestWebviewUrl (unittest .TestCase ):
8180 WV = "https://app.codeboarding.org"
8281
83- def test_link_built_with_head_ref_and_compare_base (self ):
84- link = bc .build_webview_link (self .WV , "Org" , "Repo" , "headsha" , "basesha" )
85- self .assertIn ("https://app.codeboarding.org/?" , link )
86- self .assertIn ("repo=Org%2FRepo" , link )
87- self .assertIn ("ref=headsha" , link )
88- self .assertIn ("compare=basesha" , link )
82+ def test_url_built_with_head_ref_and_compare_base (self ):
83+ url = bc .webview_url (self .WV , "Org" , "Repo" , "headsha" , "basesha" )
84+ self .assertIn ("https://app.codeboarding.org/?" , url )
85+ self .assertIn ("repo=Org%2FRepo" , url )
86+ self .assertIn ("ref=headsha" , url )
87+ self .assertIn ("compare=basesha" , url )
88+ self .assertFalse (url .startswith ("π" )) # a bare URL now, not a markdown line
8989
90- def test_link_omits_compare_when_no_base (self ):
91- link = bc .build_webview_link (self .WV , "o" , "r" , "headsha" , "" )
92- self .assertIn ("ref=headsha" , link )
93- self .assertNotIn ("compare=" , link )
90+ def test_url_omits_compare_when_no_base (self ):
91+ url = bc .webview_url (self .WV , "o" , "r" , "headsha" , "" )
92+ self .assertIn ("ref=headsha" , url )
93+ self .assertNotIn ("compare=" , url )
9494
95- def test_link_none_without_head_sha_or_base (self ):
96- self .assertIsNone (bc .build_webview_link (self .WV , "o" , "r" , "" , "basesha" ))
97- self .assertIsNone (bc .build_webview_link ("" , "o" , "r" , "headsha" , "basesha" ))
95+ def test_url_none_without_head_sha_or_base (self ):
96+ self .assertIsNone (bc .webview_url (self .WV , "o" , "r" , "" , "basesha" ))
97+ self .assertIsNone (bc .webview_url ("" , "o" , "r" , "headsha" , "basesha" ))
9898
99- def test_cta_emits_webview_line_when_ready (self ):
99+ def test_cta_includes_browser_link_when_ready (self ):
100100 out = bc .build_cta (
101101 "" ,
102102 "Org" ,
@@ -110,10 +110,12 @@ def test_cta_emits_webview_line_when_ready(self):
110110 webview_ready = True ,
111111 )
112112 self .assertIn ("Explore this PR" , out )
113+ self .assertIn ("your [**browser**](" , out )
113114 self .assertIn ("ref=headsha" , out )
114115 self .assertIn ("compare=basesha" , out )
116+ self .assertIn ("VS Code" , out ) # editor merged into the same line
115117
116- def test_cta_omits_webview_line_when_not_ready (self ):
118+ def test_cta_omits_browser_link_when_not_ready (self ):
117119 # Fork PR / head analysis not committed -> webview can't fetch at head SHA.
118120 out = bc .build_cta (
119121 "" ,
@@ -127,11 +129,12 @@ def test_cta_omits_webview_line_when_not_ready(self):
127129 base_sha = "basesha" ,
128130 webview_ready = False ,
129131 )
130- self .assertNotIn ("Explore this PR" , out )
131- # Editor CTA is still present regardless.
132- self .assertIn ("Open in VS Code" , out )
132+ self .assertNotIn ("ref=headsha" , out ) # no browser link
133+ self .assertNotIn ("[**browser**]" , out )
134+ self .assertIn ("Explore this PR" , out ) # the line is still there, editor-only
135+ self .assertIn ("VS Code" , out )
133136
134- def test_cta_omits_webview_line_when_ready_but_no_base_url (self ):
137+ def test_cta_omits_browser_link_when_ready_but_no_base_url (self ):
135138 out = bc .build_cta (
136139 "" ,
137140 "Org" ,
@@ -144,7 +147,45 @@ def test_cta_omits_webview_line_when_ready_but_no_base_url(self):
144147 base_sha = "basesha" ,
145148 webview_ready = True ,
146149 )
147- self .assertNotIn ("Explore this PR" , out )
150+ self .assertNotIn ("[**browser**]" , out )
151+ self .assertNotIn ("ref=headsha" , out )
152+
153+
154+ class TestJoinOr (unittest .TestCase ):
155+ def test_join_shapes (self ):
156+ self .assertEqual (bc ._join_or (["a" ]), "a" )
157+ self .assertEqual (bc ._join_or (["a" , "b" ]), "a or b" )
158+ self .assertEqual (bc ._join_or (["a" , "b" , "c" ]), "a, b, or c" )
159+
160+
161+ class TestMergedExploreLine (unittest .TestCase ):
162+ WV = "https://app.codeboarding.org"
163+
164+ def _ready (self , repo , cta = "" ):
165+ return bc .build_cta (
166+ cta , "o" , "r" , "1" , repo , webview_base = self .WV , head_sha = "h" , base_sha = "b" , webview_ready = True
167+ )
168+
169+ def test_browser_and_single_editor_joined_with_or (self ):
170+ out = self ._ready (repo_with ()) # default VS Code
171+ self .assertIn ("in your [**browser**](" , out )
172+ self .assertIn (") or [**VS Code**](" , out ) # browser <or> editor on one line
173+
174+ def test_editor_only_has_no_your_and_no_browser (self ):
175+ out = bc .build_cta ("" , "o" , "r" , "1" , repo_with ()) # no webview
176+ self .assertIn ("architecture in [**VS Code**](" , out ) # "in <editor>" with no "your"
177+ self .assertNotIn ("browser" , out )
178+
179+ def test_browser_and_two_editors_use_oxford_or (self ):
180+ out = self ._ready (repo_with (".vscode" , ".cursor" ))
181+ self .assertIn ("your [**browser**](" , out )
182+ self .assertIn (", or [**Cursor**](" , out ) # 3 targets -> ", or" before the last
183+
184+ def test_two_editors_no_browser_joined_with_or (self ):
185+ out = bc .build_cta ("" , "o" , "r" , "1" , repo_with (".vscode" , ".cursor" ))
186+ self .assertIn (" or [**Cursor**](" , out )
187+ self .assertNotIn (", or [**Cursor**]" , out ) # 2 targets -> plain "or", no Oxford comma
188+ self .assertNotIn ("browser" , out )
148189
149190
150191if __name__ == "__main__" :
0 commit comments