@@ -2,7 +2,7 @@ import { promises as fs } from 'fs';
22import * as os from 'os' ;
33import * as path from 'path' ;
44import { env } from 'process' ;
5- import { execWithEnv } from '../../utils/process' ;
5+ import { execAndCaptureError , execWithEnv } from '../../utils/process' ;
66
77const AUTOCOMPLETION_PROMPT = / W o u l d y o u l i k e t o e n a b l e a u t o c o m p l e t i o n \? / ;
88const DEFAULT_ENV = Object . freeze ( {
@@ -83,6 +83,161 @@ export default async function () {
8383 'CLI printed that it successfully set up autocompletion when it actually' + " didn't." ,
8484 ) ;
8585 }
86+
87+ if ( ! stdout . includes ( "Ok, you won't be prompted again." ) ) {
88+ throw new Error ( 'CLI did not inform the user they will not be prompted again.' ) ;
89+ }
90+ } ) ;
91+
92+ // Does *not* prompt if the user already accepted (even if they delete the completion config).
93+ await mockHome ( async ( home ) => {
94+ const bashrc = path . join ( home , '.bashrc' ) ;
95+ await fs . writeFile ( bashrc , '# Other commands...' ) ;
96+
97+ const { stdout : stdout1 } = await execWithEnv (
98+ 'ng' ,
99+ [ 'version' ] ,
100+ {
101+ ...DEFAULT_ENV ,
102+ SHELL : '/bin/bash' ,
103+ HOME : home ,
104+ } ,
105+ 'y' /* stdin: accept prompt */ ,
106+ ) ;
107+
108+ if ( ! AUTOCOMPLETION_PROMPT . test ( stdout1 ) ) {
109+ throw new Error ( 'First execution did not prompt for autocompletion setup.' ) ;
110+ }
111+
112+ const bashrcContents1 = await fs . readFile ( bashrc , 'utf-8' ) ;
113+ if ( ! bashrcContents1 . includes ( 'source <(ng completion)' ) ) {
114+ throw new Error (
115+ '`~/.bashrc` file was not updated after the user accepted the autocompletion' +
116+ ` prompt. Contents:\n${ bashrcContents1 } ` ,
117+ ) ;
118+ }
119+
120+ // User modifies their configuration and removes `ng completion`.
121+ await fs . writeFile ( bashrc , '# Some new commands...' ) ;
122+
123+ const { stdout : stdout2 } = await execWithEnv ( 'ng' , [ 'version' ] , {
124+ ...DEFAULT_ENV ,
125+ SHELL : '/bin/bash' ,
126+ HOME : home ,
127+ } ) ;
128+
129+ if ( AUTOCOMPLETION_PROMPT . test ( stdout2 ) ) {
130+ throw new Error (
131+ 'Subsequent execution after rejecting autocompletion setup prompted again' +
132+ ' when it should not have.' ,
133+ ) ;
134+ }
135+
136+ const bashrcContents2 = await fs . readFile ( bashrc , 'utf-8' ) ;
137+ if ( bashrcContents2 !== '# Some new commands...' ) {
138+ throw new Error (
139+ '`~/.bashrc` file was incorrectly modified when using a modified `~/.bashrc`' +
140+ ` after previously accepting the autocompletion prompt. Contents:\n${ bashrcContents2 } ` ,
141+ ) ;
142+ }
143+ } ) ;
144+
145+ // Does *not* prompt if the user already rejected.
146+ await mockHome ( async ( home ) => {
147+ const bashrc = path . join ( home , '.bashrc' ) ;
148+ await fs . writeFile ( bashrc , '# Other commands...' ) ;
149+
150+ const { stdout : stdout1 } = await execWithEnv (
151+ 'ng' ,
152+ [ 'version' ] ,
153+ {
154+ ...DEFAULT_ENV ,
155+ SHELL : '/bin/bash' ,
156+ HOME : home ,
157+ } ,
158+ 'n' /* stdin: reject prompt */ ,
159+ ) ;
160+
161+ if ( ! AUTOCOMPLETION_PROMPT . test ( stdout1 ) ) {
162+ throw new Error ( 'First execution did not prompt for autocompletion setup.' ) ;
163+ }
164+
165+ const { stdout : stdout2 } = await execWithEnv ( 'ng' , [ 'version' ] , {
166+ ...DEFAULT_ENV ,
167+ SHELL : '/bin/bash' ,
168+ HOME : home ,
169+ } ) ;
170+
171+ if ( AUTOCOMPLETION_PROMPT . test ( stdout2 ) ) {
172+ throw new Error (
173+ 'Subsequent execution after rejecting autocompletion setup prompted again' +
174+ ' when it should not have.' ,
175+ ) ;
176+ }
177+
178+ const bashrcContents = await fs . readFile ( bashrc , 'utf-8' ) ;
179+ if ( bashrcContents !== '# Other commands...' ) {
180+ throw new Error (
181+ '`~/.bashrc` file was incorrectly modified when the user never accepted the' +
182+ ` autocompletion prompt. Contents:\n${ bashrcContents } ` ,
183+ ) ;
184+ }
185+ } ) ;
186+
187+ // Prompts user again on subsequent execution after accepting prompt but failing to setup.
188+ await mockHome ( async ( home ) => {
189+ const bashrc = path . join ( home , '.bashrc' ) ;
190+ await fs . writeFile ( bashrc , '# Other commands...' ) ;
191+
192+ // Make `~/.bashrc` readonly. This is enough for the CLI to verify that the file exists and
193+ // `ng completion` is not in it, but will fail when actually trying to modify the file.
194+ await fs . chmod ( bashrc , 0o444 ) ;
195+
196+ const err = await execAndCaptureError (
197+ 'ng' ,
198+ [ 'version' ] ,
199+ {
200+ ...DEFAULT_ENV ,
201+ SHELL : '/bin/bash' ,
202+ HOME : home ,
203+ } ,
204+ 'y' /* stdin: accept prompt */ ,
205+ ) ;
206+
207+ if ( ! err . message . includes ( 'Failed to append autocompletion setup' ) ) {
208+ throw new Error (
209+ `Failed first execution did not print the expected error message. Actual:\n${ err . message } ` ,
210+ ) ;
211+ }
212+
213+ // User corrects file permissions between executions.
214+ await fs . chmod ( bashrc , 0o777 ) ;
215+
216+ const { stdout : stdout2 } = await execWithEnv (
217+ 'ng' ,
218+ [ 'version' ] ,
219+ {
220+ ...DEFAULT_ENV ,
221+ SHELL : '/bin/bash' ,
222+ HOME : home ,
223+ } ,
224+ 'y' /* stdin: accept prompt */ ,
225+ ) ;
226+
227+ if ( ! AUTOCOMPLETION_PROMPT . test ( stdout2 ) ) {
228+ throw new Error (
229+ 'Subsequent execution after failed autocompletion setup did not prompt again when it should' +
230+ ' have.' ,
231+ ) ;
232+ }
233+
234+ const bashrcContents = await fs . readFile ( bashrc , 'utf-8' ) ;
235+ if ( ! bashrcContents . includes ( 'ng completion' ) ) {
236+ throw new Error (
237+ '`~/.bashrc` file does not include `ng completion` after the user never accepted the' +
238+ ` autocompletion prompt a second time. Contents:\n${ bashrcContents } ` ,
239+ ) ;
240+ }
86241 } ) ;
87242
88243 // Does *not* prompt user for CI executions.
0 commit comments