1+ import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest' ;
2+ import {
3+ SUPPORTED_BROWSERS ,
4+ SUPPORTED_PLATFORMS ,
5+ isHelpRequested ,
6+ normalizeGitUrl ,
7+ getPullRequestUrl ,
8+ getBrowser ,
9+ displayHelp ,
10+ } from './create-pull-request.js' ;
11+
12+ // Mock the dependencies
13+ vi . mock ( 'current-git-branch' , ( ) => ( {
14+ default : vi . fn ( ( ) => 'main' ) ,
15+ } ) ) ;
16+
17+ vi . mock ( 'git-remote-origin-url' , ( ) => ( {
18+ default : vi . fn ( ( ) => Promise . resolve ( 'https://github.com/user/repo.git' ) ) ,
19+ } ) ) ;
20+
21+ vi . mock ( 'open' , ( ) => ( {
22+ default : vi . fn ( ( ) => Promise . resolve ( ) ) ,
23+ } ) ) ;
24+
25+ vi . mock ( 'chalk' , ( ) => ( {
26+ default : {
27+ hex : vi . fn ( ( ) => vi . fn ( ( text ) => text ) ) ,
28+ red : vi . fn ( ( text ) => text ) ,
29+ green : vi . fn ( ( text ) => text ) ,
30+ blue : vi . fn ( ( text ) => text ) ,
31+ bold : vi . fn ( ( text ) => text ) ,
32+ } ,
33+ } ) ) ;
34+
35+ describe ( 'create-pull-request CLI' , ( ) => {
36+ let originalArgv ;
37+ let consoleSpy ;
38+
39+ beforeEach ( ( ) => {
40+ // Store original process.argv
41+ originalArgv = process . argv ;
42+ // Mock console.log to avoid output during tests
43+ consoleSpy = vi . spyOn ( console , 'log' ) . mockImplementation ( ( ) => { } ) ;
44+ } ) ;
45+
46+ afterEach ( ( ) => {
47+ // Restore original process.argv
48+ process . argv = originalArgv ;
49+ // Restore console.log
50+ consoleSpy . mockRestore ( ) ;
51+ vi . clearAllMocks ( ) ;
52+ } ) ;
53+
54+ describe ( 'Constants' , ( ) => {
55+ it ( 'should have correct supported browsers' , ( ) => {
56+ expect ( SUPPORTED_BROWSERS ) . toEqual ( {
57+ chrome : 'google chrome' ,
58+ firefox : 'firefox' ,
59+ 'firefox-dev' : 'firefox developer edition' ,
60+ edge : 'microsoft edge' ,
61+ safari : 'safari' ,
62+ opera : 'opera' ,
63+ brave : 'brave browser' ,
64+ } ) ;
65+ } ) ;
66+
67+ it ( 'should have correct supported platforms' , ( ) => {
68+ expect ( Object . keys ( SUPPORTED_PLATFORMS ) ) . toEqual ( [
69+ 'github.com' ,
70+ 'bitbucket.org' ,
71+ 'gitlab.com' ,
72+ ] ) ;
73+ } ) ;
74+
75+ it ( 'should generate correct GitHub URL' , ( ) => {
76+ const githubHandler = SUPPORTED_PLATFORMS [ 'github.com' ] ;
77+ expect ( githubHandler ( 'https://github.com/user/repo' , 'main' ) ) . toBe (
78+ 'https://github.com/user/repo/pull/new/main'
79+ ) ;
80+ } ) ;
81+
82+ it ( 'should generate correct Bitbucket URL' , ( ) => {
83+ const bitbucketHandler = SUPPORTED_PLATFORMS [ 'bitbucket.org' ] ;
84+ expect ( bitbucketHandler ( 'https://bitbucket.org/user/repo' , 'main' ) ) . toBe (
85+ 'https://bitbucket.org/user/repo/pull-requests/new?source=main&t=1#diff'
86+ ) ;
87+ } ) ;
88+
89+ it ( 'should generate correct GitLab URL' , ( ) => {
90+ const gitlabHandler = SUPPORTED_PLATFORMS [ 'gitlab.com' ] ;
91+ expect ( gitlabHandler ( 'https://gitlab.com/user/repo' , 'main' ) ) . toBe (
92+ 'https://gitlab.com/user/repo/-/merge_requests/new?merge_request[source_branch]=main'
93+ ) ;
94+ } ) ;
95+ } ) ;
96+
97+ describe ( 'isHelpRequested' , ( ) => {
98+ it ( 'should return true for --help flag' , ( ) => {
99+ process . argv = [ 'node' , 'script.js' , '--help' ] ;
100+ expect ( isHelpRequested ( ) ) . toBe ( true ) ;
101+ } ) ;
102+
103+ it ( 'should return true for -h flag' , ( ) => {
104+ process . argv = [ 'node' , 'script.js' , '-h' ] ;
105+ expect ( isHelpRequested ( ) ) . toBe ( true ) ;
106+ } ) ;
107+
108+ it ( 'should return false for no flags' , ( ) => {
109+ process . argv = [ 'node' , 'script.js' ] ;
110+ expect ( isHelpRequested ( ) ) . toBe ( false ) ;
111+ } ) ;
112+
113+ it ( 'should return false for other flags' , ( ) => {
114+ process . argv = [ 'node' , 'script.js' , 'chrome' ] ;
115+ expect ( isHelpRequested ( ) ) . toBe ( false ) ;
116+ } ) ;
117+
118+ it ( 'should return true when help flag is present with other args' , ( ) => {
119+ process . argv = [ 'node' , 'script.js' , 'chrome' , '--help' ] ;
120+ expect ( isHelpRequested ( ) ) . toBe ( true ) ;
121+ } ) ;
122+ } ) ;
123+
124+ describe ( 'normalizeGitUrl' , ( ) => {
125+ it ( 'should convert SSH URL to HTTPS' , ( ) => {
126+ const sshUrl = '[email protected] :user/repo.git' ; 127+ const expected = 'https://github.com/user/repo' ;
128+ expect ( normalizeGitUrl ( sshUrl ) ) . toBe ( expected ) ;
129+ } ) ;
130+
131+ it ( 'should convert SSH URL with .org domain' , ( ) => {
132+ const sshUrl = '[email protected] :user/repo.git' ; 133+ const expected = 'https://bitbucket.org/user/repo' ;
134+ expect ( normalizeGitUrl ( sshUrl ) ) . toBe ( expected ) ;
135+ } ) ;
136+
137+ it ( 'should remove .git suffix from HTTPS URL' , ( ) => {
138+ const httpsUrl = 'https://github.com/user/repo.git' ;
139+ const expected = 'https://github.com/user/repo' ;
140+ expect ( normalizeGitUrl ( httpsUrl ) ) . toBe ( expected ) ;
141+ } ) ;
142+
143+ it ( 'should handle HTTPS URL without .git suffix' , ( ) => {
144+ const httpsUrl = 'https://github.com/user/repo' ;
145+ const expected = 'https://github.com/user/repo' ;
146+ expect ( normalizeGitUrl ( httpsUrl ) ) . toBe ( expected ) ;
147+ } ) ;
148+
149+ it ( 'should handle URL with path' , ( ) => {
150+ const url = '[email protected] :group/subgroup/repo.git' ; 151+ const expected = 'https://gitlab.com/group/subgroup/repo' ;
152+ expect ( normalizeGitUrl ( url ) ) . toBe ( expected ) ;
153+ } ) ;
154+ } ) ;
155+
156+ describe ( 'getPullRequestUrl' , ( ) => {
157+ it ( 'should generate GitHub pull request URL' , ( ) => {
158+ const repoUrl = 'https://github.com/user/repo' ;
159+ const expected = 'https://github.com/user/repo/pull/new/main' ;
160+ expect ( getPullRequestUrl ( repoUrl ) ) . toBe ( expected ) ;
161+ } ) ;
162+
163+ it ( 'should generate Bitbucket pull request URL' , ( ) => {
164+ const repoUrl = 'https://bitbucket.org/user/repo' ;
165+ const expected = 'https://bitbucket.org/user/repo/pull-requests/new?source=main&t=1#diff' ;
166+ expect ( getPullRequestUrl ( repoUrl ) ) . toBe ( expected ) ;
167+ } ) ;
168+
169+ it ( 'should generate GitLab merge request URL' , ( ) => {
170+ const repoUrl = 'https://gitlab.com/user/repo' ;
171+ const expected = 'https://gitlab.com/user/repo/-/merge_requests/new?merge_request[source_branch]=main' ;
172+ expect ( getPullRequestUrl ( repoUrl ) ) . toBe ( expected ) ;
173+ } ) ;
174+
175+ it ( 'should return empty string for unsupported platform' , ( ) => {
176+ const repoUrl = 'https://example.com/user/repo' ;
177+ expect ( getPullRequestUrl ( repoUrl ) ) . toBe ( '' ) ;
178+ } ) ;
179+
180+ it ( 'should throw error for invalid URL' , ( ) => {
181+ const invalidUrl = 'not-a-url' ;
182+ expect ( ( ) => getPullRequestUrl ( invalidUrl ) ) . toThrow ( 'Invalid repository URL' ) ;
183+ } ) ;
184+
185+ it ( 'should handle URLs with paths' , ( ) => {
186+ const repoUrl = 'https://github.com/org/team/repo' ;
187+ const expected = 'https://github.com/org/team/repo/pull/new/main' ;
188+ expect ( getPullRequestUrl ( repoUrl ) ) . toBe ( expected ) ;
189+ } ) ;
190+ } ) ;
191+
192+ describe ( 'getBrowser' , ( ) => {
193+ it ( 'should return browser name for valid browser' , ( ) => {
194+ process . argv = [ 'node' , 'script.js' , 'chrome' ] ;
195+ expect ( getBrowser ( ) ) . toBe ( 'google chrome' ) ;
196+ } ) ;
197+
198+ it ( 'should return firefox developer edition for firefox-dev' , ( ) => {
199+ process . argv = [ 'node' , 'script.js' , 'firefox-dev' ] ;
200+ expect ( getBrowser ( ) ) . toBe ( 'firefox developer edition' ) ;
201+ } ) ;
202+
203+ it ( 'should return brave browser for brave' , ( ) => {
204+ process . argv = [ 'node' , 'script.js' , 'brave' ] ;
205+ expect ( getBrowser ( ) ) . toBe ( 'brave browser' ) ;
206+ } ) ;
207+
208+ it ( 'should return null for no browser argument' , ( ) => {
209+ process . argv = [ 'node' , 'script.js' ] ;
210+ expect ( getBrowser ( ) ) . toBe ( null ) ;
211+ } ) ;
212+
213+ it ( 'should return null for help flag' , ( ) => {
214+ process . argv = [ 'node' , 'script.js' , '--help' ] ;
215+ expect ( getBrowser ( ) ) . toBe ( null ) ;
216+ } ) ;
217+
218+ it ( 'should return null for -h flag' , ( ) => {
219+ process . argv = [ 'node' , 'script.js' , '-h' ] ;
220+ expect ( getBrowser ( ) ) . toBe ( null ) ;
221+ } ) ;
222+
223+ it ( 'should return null and log warning for invalid browser' , ( ) => {
224+ process . argv = [ 'node' , 'script.js' , 'invalid-browser' ] ;
225+ const result = getBrowser ( ) ;
226+
227+ expect ( result ) . toBe ( null ) ;
228+ expect ( consoleSpy ) . toHaveBeenCalledWith (
229+ expect . stringContaining ( 'Browser "invalid-browser" is not supported' )
230+ ) ;
231+ } ) ;
232+
233+ it ( 'should handle all supported browsers' , ( ) => {
234+ const browserTests = [
235+ [ 'chrome' , 'google chrome' ] ,
236+ [ 'firefox' , 'firefox' ] ,
237+ [ 'firefox-dev' , 'firefox developer edition' ] ,
238+ [ 'edge' , 'microsoft edge' ] ,
239+ [ 'safari' , 'safari' ] ,
240+ [ 'opera' , 'opera' ] ,
241+ [ 'brave' , 'brave browser' ] ,
242+ ] ;
243+
244+ browserTests . forEach ( ( [ input , expected ] ) => {
245+ process . argv = [ 'node' , 'script.js' , input ] ;
246+ expect ( getBrowser ( ) ) . toBe ( expected ) ;
247+ } ) ;
248+ } ) ;
249+ } ) ;
250+
251+ describe ( 'displayHelp' , ( ) => {
252+ it ( 'should display help information' , ( ) => {
253+ displayHelp ( ) ;
254+
255+ expect ( consoleSpy ) . toHaveBeenCalledWith (
256+ expect . stringContaining ( 'Create Pull Request CLI' )
257+ ) ;
258+ expect ( consoleSpy ) . toHaveBeenCalledWith (
259+ expect . stringContaining ( 'Usage:' )
260+ ) ;
261+ expect ( consoleSpy ) . toHaveBeenCalledWith (
262+ expect . stringContaining ( 'chrome, firefox, firefox-dev, edge, safari, opera, brave' )
263+ ) ;
264+ expect ( consoleSpy ) . toHaveBeenCalledWith (
265+ expect . stringContaining ( 'github.com, bitbucket.org, gitlab.com' )
266+ ) ;
267+ } ) ;
268+ } ) ;
269+
270+ describe ( 'Integration tests' , ( ) => {
271+ it ( 'should handle complete workflow for GitHub repo' , ( ) => {
272+ const sshUrl = '[email protected] :user/repo.git' ; 273+ const normalizedUrl = normalizeGitUrl ( sshUrl ) ;
274+ const pullRequestUrl = getPullRequestUrl ( normalizedUrl ) ;
275+
276+ expect ( normalizedUrl ) . toBe ( 'https://github.com/user/repo' ) ;
277+ expect ( pullRequestUrl ) . toBe ( 'https://github.com/user/repo/pull/new/main' ) ;
278+ } ) ;
279+
280+ it ( 'should handle complete workflow for GitLab repo' , ( ) => {
281+ const httpsUrl = 'https://gitlab.com/group/project.git' ;
282+ const normalizedUrl = normalizeGitUrl ( httpsUrl ) ;
283+ const pullRequestUrl = getPullRequestUrl ( normalizedUrl ) ;
284+
285+ expect ( normalizedUrl ) . toBe ( 'https://gitlab.com/group/project' ) ;
286+ expect ( pullRequestUrl ) . toBe ( 'https://gitlab.com/group/project/-/merge_requests/new?merge_request[source_branch]=main' ) ;
287+ } ) ;
288+
289+ it ( 'should handle browser selection with help flag' , ( ) => {
290+ process . argv = [ 'node' , 'script.js' , '--help' ] ;
291+
292+ expect ( isHelpRequested ( ) ) . toBe ( true ) ;
293+ expect ( getBrowser ( ) ) . toBe ( null ) ;
294+ } ) ;
295+
296+ it ( 'should handle browser selection without help flag' , ( ) => {
297+ process . argv = [ 'node' , 'script.js' , 'firefox' ] ;
298+
299+ expect ( isHelpRequested ( ) ) . toBe ( false ) ;
300+ expect ( getBrowser ( ) ) . toBe ( 'firefox' ) ;
301+ } ) ;
302+ } ) ;
303+ } ) ;
0 commit comments