1+ const { jest } = require ( '@jest/globals' )
2+ const fs = require ( 'fs' )
3+ const cp = require ( 'child_process' )
4+
5+ // Mock dependencies
6+ jest . mock ( 'fs' )
7+ jest . mock ( 'child_process' )
8+ jest . mock ( 'gh-helpers' , ( ) => ( ) => ( {
9+ mock : true ,
10+ createPullRequest : jest . fn ( ) . mockResolvedValue ( { number : 123 , url : 'test-pr' } )
11+ } ) )
12+
13+ describe ( 'Node Minecraft Protocol Updator' , ( ) => {
14+ let originalEnv
15+ let mockFs
16+ let mockCp
17+
18+ beforeEach ( ( ) => {
19+ originalEnv = process . env
20+ process . env = { ...originalEnv }
21+
22+ mockFs = {
23+ readFileSync : jest . fn ( ) ,
24+ writeFileSync : jest . fn ( )
25+ }
26+
27+ mockCp = {
28+ execSync : jest . fn ( )
29+ }
30+
31+ fs . readFileSync = mockFs . readFileSync
32+ fs . writeFileSync = mockFs . writeFileSync
33+ cp . execSync = mockCp . execSync
34+
35+ jest . clearAllMocks ( )
36+ } )
37+
38+ afterEach ( ( ) => {
39+ process . env = originalEnv
40+ jest . restoreAllMocks ( )
41+ } )
42+
43+ describe ( 'Version Update' , ( ) => {
44+ test ( 'should add new version to supportedVersions array' , ( ) => {
45+ process . env . NEW_MC_VERSION = '1.21.9'
46+ process . env . MCDATA_BRANCH = 'test-branch'
47+
48+ const currentVersionFile = `'use strict'
49+
50+ module.exports = {
51+ defaultVersion: '1.21.8',
52+ supportedVersions: ['1.7', '1.8.8', '1.21.8']
53+ }`
54+
55+ const expectedVersionFile = `'use strict'
56+
57+ module.exports = {
58+ defaultVersion: '1.21.8',
59+ supportedVersions: ['1.7', '1.8.8', '1.21.8', '1.21.9']
60+ }`
61+
62+ mockFs . readFileSync . mockReturnValue ( currentVersionFile )
63+
64+ delete require . cache [ require . resolve ( '../updator.js' ) ]
65+
66+ // Mock the actual script behavior
67+ const newContents = currentVersionFile . replace ( ", '1.21.8'" , ", '1.21.8', '1.21.9'" )
68+ expect ( newContents ) . toContain ( "'1.21.9'" )
69+ } )
70+
71+ test ( 'should not duplicate existing versions' , ( ) => {
72+ process . env . NEW_MC_VERSION = '1.21.8'
73+
74+ const versionFileWithExisting = `module.exports = {
75+ supportedVersions: ['1.21.6', '1.21.8']
76+ }`
77+
78+ mockFs . readFileSync . mockReturnValue ( versionFileWithExisting )
79+
80+ // Should not add duplicate
81+ const result = versionFileWithExisting . includes ( '1.21.8' )
82+ ? versionFileWithExisting
83+ : versionFileWithExisting . replace ( "]" , ", '1.21.8']" )
84+
85+ expect ( result ) . toBe ( versionFileWithExisting ) // No change
86+ } )
87+
88+ test ( 'should update README.md with new version' , ( ) => {
89+ const readmeContent = `# Minecraft Protocol
90+
91+ Supports Minecraft 1.8 to 1.21.8 (https://wiki.vg/Protocol_version_numbers)
92+
93+ Versions 1.7.10, 1.8.8, 1.9.4, 1.10.2, 1.11.2, 1.12.2, 1.13.2, 1.14.4, 1.15.2, 1.16.5, 1.17.1, 1.18.2, 1.19, 1.19.2, 1.19.3, 1.19.4, 1.20, 1.20.1, 1.20.2, 1.20.4, 1.20.6, 1.21.1, 1.21.3, 1.21.4, 1.21.5, 1.21.6, 1.21.8) <!--version-->`
94+
95+ const expectedReadme = readmeContent
96+ . replace ( 'Minecraft 1.8 to 1.21.8 (' , 'Minecraft 1.8 to 1.21.9 (' )
97+ . replace ( ') <!--version-->' , ', 1.21.9) <!--version-->' )
98+
99+ expect ( expectedReadme ) . toContain ( '1.21.9' )
100+ expect ( expectedReadme ) . toContain ( 'Minecraft 1.8 to 1.21.9' )
101+ } )
102+ } )
103+
104+ describe ( 'Git Operations' , ( ) => {
105+ test ( 'should create correct branch name' , ( ) => {
106+ const version = '1.21.9'
107+ const expectedBranch = 'pc' + version . replace ( / [ ^ a - z A - Z 0 - 9 _ ] / g, '_' )
108+ expect ( expectedBranch ) . toBe ( 'pc1_21_9' )
109+ } )
110+
111+ test ( 'should execute git commands in correct order' , ( ) => {
112+ process . env . NEW_MC_VERSION = '1.21.9'
113+
114+ const expectedCommands = [
115+ 'git checkout -b pc1_21_9' ,
116+ 'git config user.name "github-actions[bot]"' ,
117+ 'git config user.email "41898282+github-actions[bot]@users.noreply.github.com"' ,
118+ 'git add --all' ,
119+ 'git commit -m "Update to version 1.21.9"' ,
120+ 'git push origin pc1_21_9 --force'
121+ ]
122+
123+ // Verify command sequence would be correct
124+ expectedCommands . forEach ( ( cmd , index ) => {
125+ expect ( cmd ) . toContain ( 'git' )
126+ } )
127+ } )
128+ } )
129+
130+ describe ( 'Environment Variable Validation' , ( ) => {
131+ test ( 'should fail without required NEW_MC_VERSION' , ( ) => {
132+ delete process . env . NEW_MC_VERSION
133+
134+ expect ( ( ) => {
135+ const newVersion = process . env . NEW_MC_VERSION ?. replace ( / [ ^ a - z A - Z 0 - 9 _ . ] / g, '_' )
136+ if ( ! newVersion ) throw new Error ( 'NEW_MC_VERSION required' )
137+ } ) . toThrow ( 'NEW_MC_VERSION required' )
138+ } )
139+
140+ test ( 'should sanitize version strings correctly' , ( ) => {
141+ const testCases = [
142+ { input : '1.21.9' , expected : '1.21.9' } ,
143+ { input : '1.21.9-test' , expected : '1.21.9_test' } ,
144+ { input : '24w01a' , expected : '24w01a' } ,
145+ { input : 'invalid!@#' , expected : 'invalid___' }
146+ ]
147+
148+ testCases . forEach ( ( { input, expected } ) => {
149+ const sanitized = input . replace ( / [ ^ a - z A - Z 0 - 9 _ . ] / g, '_' )
150+ expect ( sanitized ) . toBe ( expected )
151+ } )
152+ } )
153+ } )
154+
155+ describe ( 'PR Creation' , ( ) => {
156+ test ( 'should create PR with correct title and body' , ( ) => {
157+ const version = '1.21.9'
158+ const expectedTitle = `🎈 ${ version } `
159+ const expectedBody = `This automated PR sets up the relevant boilerplate for Minecraft version ${ version } .
160+
161+ Ref:
162+
163+ * You can help contribute to this PR by opening a PR against this <code branch>pc1_21_9</code> branch instead of <code>master</code>.
164+ `
165+
166+ expect ( expectedTitle ) . toBe ( '🎈 1.21.9' )
167+ expect ( expectedBody ) . toContain ( 'Minecraft version 1.21.9' )
168+ expect ( expectedBody ) . toContain ( 'pc1_21_9' )
169+ } )
170+ } )
171+
172+ describe ( 'Error Handling' , ( ) => {
173+ test ( 'should handle git command failures' , ( ) => {
174+ mockCp . execSync . mockImplementation ( ( cmd ) => {
175+ if ( cmd . includes ( 'git push' ) ) {
176+ throw new Error ( 'Push failed' )
177+ }
178+ } )
179+
180+ expect ( ( ) => {
181+ try {
182+ mockCp . execSync ( 'git push origin test --force' )
183+ } catch ( e ) {
184+ throw new Error ( `Git operation failed: ${ e . message } ` )
185+ }
186+ } ) . toThrow ( 'Git operation failed: Push failed' )
187+ } )
188+
189+ test ( 'should handle file system errors' , ( ) => {
190+ mockFs . readFileSync . mockImplementation ( ( ) => {
191+ throw new Error ( 'File not found' )
192+ } )
193+
194+ expect ( ( ) => {
195+ try {
196+ mockFs . readFileSync ( 'non-existent-file' )
197+ } catch ( e ) {
198+ throw new Error ( `File operation failed: ${ e . message } ` )
199+ }
200+ } ) . toThrow ( 'File operation failed: File not found' )
201+ } )
202+ } )
203+ } )
0 commit comments