webdrivers 4.0.1 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,7 +31,7 @@ describe Webdrivers::Chromedriver do
31
31
  it 'does not download when offline, binary exists and matches major browser version' do
32
32
  allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
33
33
  allow(chromedriver).to receive(:exists?).and_return(true)
34
- allow(chromedriver).to receive(:chrome_version).and_return(Gem::Version.new('73.0.3683.68'))
34
+ allow(chromedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
35
35
  allow(chromedriver).to receive(:current_version).and_return(Gem::Version.new('73.0.3683.20'))
36
36
 
37
37
  chromedriver.update
@@ -44,7 +44,7 @@ describe Webdrivers::Chromedriver do
44
44
 
45
45
  allow(Webdrivers::Network).to receive(:get_response).and_return(client_error)
46
46
  allow(chromedriver).to receive(:exists?).and_return(true)
47
- allow(chromedriver).to receive(:chrome_version).and_return(Gem::Version.new('73.0.3683.68'))
47
+ allow(chromedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
48
48
  allow(chromedriver).to receive(:current_version).and_return(Gem::Version.new('73.0.3683.20'))
49
49
 
50
50
  chromedriver.update
@@ -55,7 +55,7 @@ describe Webdrivers::Chromedriver do
55
55
  it 'raises ConnectionError when offline, and binary does not match major browser version' do
56
56
  allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
57
57
  allow(chromedriver).to receive(:exists?).and_return(true)
58
- allow(chromedriver).to receive(:chrome_version).and_return(Gem::Version.new('73.0.3683.68'))
58
+ allow(chromedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
59
59
  allow(chromedriver).to receive(:current_version).and_return(Gem::Version.new('72.0.0.0'))
60
60
 
61
61
  msg = %r{Can not reach https://chromedriver.storage.googleapis.com}
@@ -108,7 +108,7 @@ describe Webdrivers::Chromedriver do
108
108
 
109
109
  it 'makes a network call if cached driver does not match the browser' do
110
110
  Webdrivers::System.cache_version('chromedriver', '71.0.3578.137')
111
- allow(chromedriver).to receive(:chrome_version).and_return(Gem::Version.new('73.0.3683.68'))
111
+ allow(chromedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
112
112
  allow(Webdrivers::Network).to receive(:get).and_return('73.0.3683.68')
113
113
  allow(Webdrivers::System).to receive(:download)
114
114
 
@@ -146,7 +146,7 @@ describe Webdrivers::Chromedriver do
146
146
  it 'returns a Gem::Version instance if binary is on the system' do
147
147
  allow(chromedriver).to receive(:exists?).and_return(true)
148
148
  allow(Webdrivers::System).to receive(:call)
149
- .with("#{chromedriver.driver_path} --version")
149
+ .with(chromedriver.driver_path, '--version')
150
150
  .and_return '71.0.3578.137'
151
151
 
152
152
  expect(chromedriver.current_version).to eq Gem::Version.new('71.0.3578.137')
@@ -155,19 +155,19 @@ describe Webdrivers::Chromedriver do
155
155
 
156
156
  describe '#latest_version' do
157
157
  it 'returns 2.41 if the browser version is less than 70' do
158
- allow(chromedriver).to receive(:chrome_version).and_return('69.0.0')
158
+ allow(chromedriver).to receive(:browser_version).and_return('69.0.0')
159
159
 
160
160
  expect(chromedriver.latest_version).to eq(Gem::Version.new('2.41'))
161
161
  end
162
162
 
163
163
  it 'returns the correct point release for a production version greater than 70' do
164
- allow(chromedriver).to receive(:chrome_version).and_return '71.0.3578.9999'
164
+ allow(chromedriver).to receive(:browser_version).and_return '71.0.3578.9999'
165
165
 
166
166
  expect(chromedriver.latest_version).to eq Gem::Version.new('71.0.3578.137')
167
167
  end
168
168
 
169
169
  it 'raises VersionError for beta version' do
170
- allow(chromedriver).to receive(:chrome_version).and_return('100.0.0')
170
+ allow(chromedriver).to receive(:browser_version).and_return('100.0.0')
171
171
  msg = 'Unable to find latest point release version for 100.0.0. '\
172
172
  'You appear to be using a non-production version of Chrome. '\
173
173
  'Please set `Webdrivers::Chromedriver.required_version = <desired driver version>` '\
@@ -177,7 +177,7 @@ describe Webdrivers::Chromedriver do
177
177
  end
178
178
 
179
179
  it 'raises VersionError for unknown version' do
180
- allow(chromedriver).to receive(:chrome_version).and_return('72.0.9999.0000')
180
+ allow(chromedriver).to receive(:browser_version).and_return('72.0.9999.0000')
181
181
  msg = 'Unable to find latest point release version for 72.0.9999. '\
182
182
  'Please set `Webdrivers::Chromedriver.required_version = <desired driver version>` '\
183
183
  'to a known chromedriver version: https://chromedriver.storage.googleapis.com/index.html'
@@ -253,8 +253,19 @@ describe Webdrivers::Chromedriver do
253
253
  describe '#driver_path' do
254
254
  it 'returns full location of binary' do
255
255
  expected_bin = "chromedriver#{'.exe' if Selenium::WebDriver::Platform.windows?}"
256
- expected_path = Webdrivers::System.escape_path("#{File.join(ENV['HOME'])}/.webdrivers/#{expected_bin}")
256
+ expected_path = File.absolute_path "#{File.join(ENV['HOME'])}/.webdrivers/#{expected_bin}"
257
257
  expect(chromedriver.driver_path).to eq(expected_path)
258
258
  end
259
259
  end
260
+
261
+ describe '#browser_version' do
262
+ it 'returns a Gem::Version object' do
263
+ expect(chromedriver.browser_version).to be_an_instance_of(Gem::Version)
264
+ end
265
+
266
+ it 'returns currently installed Chrome version' do
267
+ allow(Webdrivers::ChromeFinder).to receive(:version).and_return('72.0.0.0')
268
+ expect(chromedriver.browser_version).to be Gem::Version.new('72.0.0.0')
269
+ end
270
+ end
260
271
  end
@@ -0,0 +1,276 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Webdrivers::Edgedriver do
6
+ let(:edgedriver) { described_class }
7
+
8
+ before(:all) do # rubocop:disable RSpec/BeforeAfterAll
9
+ # Skip these tests if version of selenium-webdriver being tested with doesn't
10
+ # have Chromium based Edge support
11
+ unless defined?(Selenium::WebDriver::EdgeChrome)
12
+ skip "The current selenium-webdriver doesn't include Chromium based Edge support"
13
+ end
14
+ end
15
+
16
+ before { edgedriver.remove }
17
+
18
+ describe '#update' do
19
+ context 'when evaluating #correct_binary?' do
20
+ it 'does not download when latest version and current version match' do
21
+ allow(edgedriver).to receive(:latest_version).and_return(Gem::Version.new('72.0.0'))
22
+ allow(edgedriver).to receive(:current_version).and_return(Gem::Version.new('72.0.0'))
23
+
24
+ edgedriver.update
25
+
26
+ expect(edgedriver.send(:exists?)).to be false
27
+ end
28
+
29
+ it 'does not download when offline, binary exists and is less than v70' do
30
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
31
+ allow(edgedriver).to receive(:exists?).and_return(true)
32
+ allow(edgedriver).to receive(:current_version).and_return(Gem::Version.new(69))
33
+
34
+ edgedriver.update
35
+
36
+ expect(File.exist?(edgedriver.driver_path)).to be false
37
+ end
38
+
39
+ it 'does not download when offline, binary exists and matches major browser version' do
40
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
41
+ allow(edgedriver).to receive(:exists?).and_return(true)
42
+ allow(edgedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
43
+ allow(edgedriver).to receive(:current_version).and_return(Gem::Version.new('73.0.3683.20'))
44
+
45
+ edgedriver.update
46
+
47
+ expect(File.exist?(edgedriver.driver_path)).to be false
48
+ end
49
+
50
+ it 'does not download when get raises exception, binary exists and matches major browser version' do
51
+ client_error = instance_double(Net::HTTPNotFound, class: Net::HTTPNotFound, code: 404, message: '')
52
+
53
+ allow(Webdrivers::Network).to receive(:get_response).and_return(client_error)
54
+ allow(edgedriver).to receive(:exists?).and_return(true)
55
+ allow(edgedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
56
+ allow(edgedriver).to receive(:current_version).and_return(Gem::Version.new('73.0.3683.20'))
57
+
58
+ edgedriver.update
59
+
60
+ expect(File.exist?(edgedriver.driver_path)).to be false
61
+ end
62
+
63
+ it 'raises ConnectionError when offline, and binary does not match major browser version' do
64
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
65
+ allow(edgedriver).to receive(:exists?).and_return(true)
66
+ allow(edgedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
67
+ allow(edgedriver).to receive(:current_version).and_return(Gem::Version.new('72.0.0.0'))
68
+
69
+ msg = %r{Can not reach https://msedgedriver.azureedge.net/}
70
+ expect { edgedriver.update }.to raise_error(Webdrivers::ConnectionError, msg)
71
+ end
72
+
73
+ it 'raises ConnectionError when offline, and no binary exists' do
74
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
75
+ allow(edgedriver).to receive(:exists?).and_return(false)
76
+
77
+ msg = %r{Can not reach https://msedgedriver.azureedge.net/}
78
+ expect { edgedriver.update }.to raise_error(Webdrivers::ConnectionError, msg)
79
+ end
80
+ end
81
+
82
+ context 'when correct binary is found' do
83
+ before { allow(edgedriver).to receive(:correct_binary?).and_return(true) }
84
+
85
+ it 'does not download' do
86
+ edgedriver.update
87
+
88
+ expect(edgedriver.current_version).to be_nil
89
+ end
90
+
91
+ it 'does not raise exception if offline' do
92
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
93
+
94
+ edgedriver.update
95
+
96
+ expect(edgedriver.current_version).to be_nil
97
+ end
98
+ end
99
+
100
+ context 'when correct binary is not found' do
101
+ before { allow(edgedriver).to receive(:correct_binary?).and_return(false) }
102
+
103
+ it 'downloads binary' do
104
+ edgedriver.update
105
+
106
+ expect(edgedriver.current_version).not_to be_nil
107
+ end
108
+
109
+ it 'raises ConnectionError if offline' do
110
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
111
+
112
+ msg = %r{Can not reach https://msedgedriver.azureedge.net/}
113
+ expect { edgedriver.update }.to raise_error(Webdrivers::ConnectionError, msg)
114
+ end
115
+ end
116
+
117
+ it 'makes a network call if cached driver does not match the browser' do
118
+ Webdrivers::System.cache_version('msedgedriver', '71.0.3578.137')
119
+ allow(edgedriver).to receive(:browser_version).and_return(Gem::Version.new('73.0.3683.68'))
120
+ allow(Webdrivers::Network).to receive(:get).and_return('73.0.3683.68'.encode('UTF-16'))
121
+ allow(Webdrivers::System).to receive(:download)
122
+
123
+ edgedriver.update
124
+
125
+ expect(Webdrivers::Network).to have_received(:get).once
126
+ end
127
+
128
+ context 'when required version is 0' do
129
+ it 'downloads the latest version' do
130
+ allow(edgedriver).to receive(:latest_version).and_return(Gem::Version.new('77.0.207.0'))
131
+ edgedriver.required_version = 0
132
+ edgedriver.update
133
+ expect(edgedriver.current_version.version).to eq('77.0.207.0')
134
+ end
135
+ end
136
+
137
+ context 'when required version is nil' do
138
+ it 'downloads the latest version' do
139
+ allow(edgedriver).to receive(:latest_version).and_return(Gem::Version.new('77.0.207.0'))
140
+ edgedriver.required_version = nil
141
+ edgedriver.update
142
+ expect(edgedriver.current_version.version).to eq('77.0.207.0')
143
+ end
144
+ end
145
+ end
146
+
147
+ describe '#current_version' do
148
+ it 'returns nil if binary does not exist on the system' do
149
+ allow(edgedriver).to receive(:driver_path).and_return('')
150
+
151
+ expect(edgedriver.current_version).to be_nil
152
+ end
153
+
154
+ it 'returns a Gem::Version instance if binary is on the system' do
155
+ allow(edgedriver).to receive(:exists?).and_return(true)
156
+ allow(Webdrivers::System).to receive(:call)
157
+ .with(edgedriver.driver_path, '--version')
158
+ .and_return '71.0.3578.137'
159
+
160
+ expect(edgedriver.current_version).to eq Gem::Version.new('71.0.3578.137')
161
+ end
162
+ end
163
+
164
+ describe '#latest_version' do
165
+ it 'returns the correct point release for a production version' do
166
+ allow(edgedriver).to receive(:browser_version).and_return '77.0.207.0'
167
+
168
+ expect(edgedriver.latest_version).to be_between(Gem::Version.new('77.0.207.0'), Gem::Version.new('78'))
169
+ end
170
+
171
+ it 'raises VersionError for beta version' do
172
+ allow(edgedriver).to receive(:browser_version).and_return('100.0.0')
173
+ msg = 'Unable to find latest point release version for 100.0.0. '\
174
+ 'You appear to be using a non-production version of Edge. '\
175
+ 'Please set `Webdrivers::Edgedriver.required_version = <desired driver version>` '\
176
+ 'to a known edgedriver version: Can not reach https://msedgedriver.azureedge.net/'
177
+
178
+ expect { edgedriver.latest_version }.to raise_exception(Webdrivers::VersionError, msg)
179
+ end
180
+
181
+ it 'raises VersionError for unknown version' do
182
+ skip "MS doesn't yet support point release latest versioning."
183
+ allow(edgedriver).to receive(:browser_version).and_return('77.0.9999.0000')
184
+ msg = 'Unable to find latest point release version for 77.0.9999. '\
185
+ 'Please set `Webdrivers::Edgedriver.required_version = <desired driver version>` '\
186
+ 'to a known edgedriver version: Can not reach https://msedgedriver.azureedge.net/'
187
+
188
+ expect { edgedriver.latest_version }.to raise_exception(Webdrivers::VersionError, msg)
189
+ end
190
+
191
+ it 'raises ConnectionError when offline' do
192
+ allow(Net::HTTP).to receive(:get_response).and_raise(SocketError)
193
+
194
+ msg = %r{^Can not reach https://msedgedriver.azureedge.net}
195
+ expect { edgedriver.latest_version }.to raise_error(Webdrivers::ConnectionError, msg)
196
+ end
197
+
198
+ it 'creates cached file' do
199
+ allow(edgedriver).to receive(:browser_version).and_return('77.0.207.0')
200
+ allow(Webdrivers::Network).to receive(:get).and_return('77.0.207.0'.encode('UTF-16'))
201
+
202
+ edgedriver.latest_version
203
+ expect(File.exist?("#{Webdrivers::System.install_dir}/msedgedriver.version")).to eq true
204
+ end
205
+
206
+ it 'does not make network call if cache is valid' do
207
+ allow(Webdrivers).to receive(:cache_time).and_return(3600)
208
+ Webdrivers::System.cache_version('msedgedriver', '77.0.207.0')
209
+ allow(Webdrivers::Network).to receive(:get)
210
+
211
+ expect(edgedriver.latest_version).to eq Gem::Version.new('77.0.207.0')
212
+
213
+ expect(Webdrivers::Network).not_to have_received(:get)
214
+ end
215
+
216
+ it 'makes a network call if cache is expired' do
217
+ Webdrivers::System.cache_version('msedgedriver', '71.0.3578.137')
218
+ allow(Webdrivers::Network).to receive(:get).and_return('77.0.207.0'.encode('UTF-16'))
219
+ allow(Webdrivers::System).to receive(:valid_cache?)
220
+ allow(edgedriver).to receive(:browser_version).and_return('77.0.207.0')
221
+
222
+ expect(edgedriver.latest_version).to eq Gem::Version.new('77.0.207.0')
223
+
224
+ expect(Webdrivers::Network).to have_received(:get)
225
+ expect(Webdrivers::System).to have_received(:valid_cache?)
226
+ end
227
+ end
228
+
229
+ describe '#required_version=' do
230
+ after { edgedriver.required_version = nil }
231
+
232
+ it 'returns the version specified as a Float' do
233
+ edgedriver.required_version = 73.0
234
+
235
+ expect(edgedriver.required_version).to eq Gem::Version.new('73.0')
236
+ end
237
+
238
+ it 'returns the version specified as a String' do
239
+ edgedriver.required_version = '73.0'
240
+
241
+ expect(edgedriver.required_version).to eq Gem::Version.new('73.0')
242
+ end
243
+ end
244
+
245
+ describe '#remove' do
246
+ it 'removes existing edgedriver' do
247
+ edgedriver.update
248
+
249
+ edgedriver.remove
250
+ expect(edgedriver.current_version).to be_nil
251
+ end
252
+
253
+ it 'does not raise exception if no edgedriver found' do
254
+ expect { edgedriver.remove }.not_to raise_error
255
+ end
256
+ end
257
+
258
+ describe '#driver_path' do
259
+ it 'returns full location of binary' do
260
+ expected_bin = "msedgedriver#{'.exe' if Selenium::WebDriver::Platform.windows?}"
261
+ expected_path = File.absolute_path "#{File.join(ENV['HOME'])}/.webdrivers/#{expected_bin}"
262
+ expect(edgedriver.driver_path).to eq(expected_path)
263
+ end
264
+ end
265
+
266
+ describe '#browser_version' do
267
+ it 'returns a Gem::Version object' do
268
+ expect(edgedriver.browser_version).to be_an_instance_of(Gem::Version)
269
+ end
270
+
271
+ it 'returns currently installed Edge version' do
272
+ allow(Webdrivers::EdgeFinder).to receive(:version).and_return('72.0.0.0')
273
+ expect(edgedriver.browser_version).to be Gem::Version.new('72.0.0.0')
274
+ end
275
+ end
276
+ end
@@ -112,7 +112,7 @@ testing/geckodriver in https://hg.mozilla.org/mozilla-central.
112
112
  This program is subject to the terms of the Mozilla Public License 2.0.
113
113
  You can obtain a copy of the license at https://mozilla.org/MPL/2.0/"
114
114
 
115
- allow(Webdrivers::System).to receive(:call).with("#{geckodriver.driver_path} --version").and_return return_value
115
+ allow(Webdrivers::System).to receive(:call).with(geckodriver.driver_path, '--version').and_return return_value
116
116
 
117
117
  expect(geckodriver.current_version).to eq Gem::Version.new('0.24.0')
118
118
  end
@@ -205,7 +205,7 @@ You can obtain a copy of the license at https://mozilla.org/MPL/2.0/"
205
205
  describe '#driver_path' do
206
206
  it 'returns full location of binary' do
207
207
  expected_bin = "geckodriver#{'.exe' if Selenium::WebDriver::Platform.windows?}"
208
- expected_path = Webdrivers::System.escape_path("#{File.join(ENV['HOME'])}/.webdrivers/#{expected_bin}")
208
+ expected_path = File.absolute_path "#{File.join(ENV['HOME'])}/.webdrivers/#{expected_bin}"
209
209
  expect(geckodriver.driver_path).to eq(expected_path)
210
210
  end
211
211
  end
@@ -87,7 +87,7 @@ describe Webdrivers::IEdriver do
87
87
 
88
88
  return_value = 'something IEDriverServer.exe 3.5.1 something else'
89
89
 
90
- allow(Webdrivers::System).to receive(:call).with("#{iedriver.driver_path} --version").and_return return_value
90
+ allow(Webdrivers::System).to receive(:call).with(iedriver.driver_path, '--version').and_return return_value
91
91
 
92
92
  expect(iedriver.current_version).to eq Gem::Version.new('3.5.1')
93
93
  end
@@ -186,7 +186,7 @@ describe Webdrivers::IEdriver do
186
186
 
187
187
  describe '#driver_path' do
188
188
  it 'returns full location of binary' do
189
- expected_path = Webdrivers::System.escape_path("#{File.join(ENV['HOME'])}/.webdrivers/IEDriverServer.exe")
189
+ expected_path = File.absolute_path "#{File.join(ENV['HOME'])}/.webdrivers/IEDriverServer.exe"
190
190
  expect(iedriver.driver_path).to eq(expected_path)
191
191
  end
192
192
  end
@@ -29,15 +29,15 @@ describe Webdrivers do
29
29
  end
30
30
 
31
31
  context 'when ENV variable WD_CACHE_TIME is set' do
32
- before { described_class.cache_time = 86_400 }
32
+ before { described_class.cache_time = 3600 }
33
33
 
34
- it 'uses cache time value from ENV variable over the Webdrivers.cache_time value' do
35
- allow(ENV).to receive(:[]).with('WD_CACHE_TIME').and_return(999)
36
- expect(described_class.cache_time).to be(999)
34
+ it 'uses cache time value from Webdrivers.cache_time over the ENV variable value' do
35
+ allow(ENV).to receive(:[]).with('WD_CACHE_TIME').and_return(900)
36
+ expect(described_class.cache_time).to be(3600)
37
37
  end
38
38
 
39
39
  it 'returns cache time as an Integer' do
40
- allow(ENV).to receive(:fetch).with('WD_CACHE_TIME', 86_400).and_return('999')
40
+ allow(ENV).to receive(:fetch).with('WD_CACHE_TIME', 3600).and_return('999')
41
41
  expect(described_class.cache_time).to be_an_instance_of(Integer)
42
42
  end
43
43
  end
@@ -70,5 +70,17 @@ describe Webdrivers do
70
70
  end
71
71
  end
72
72
  end
73
+
74
+ context 'when both ENV variable WD_INSTALL_DIR and Webdrivers.install_dir are set' do
75
+ it 'uses path from Webdrivers.install_dir' do
76
+ begin
77
+ described_class.install_dir = 'my_install_dir_path'
78
+ allow(ENV).to receive(:[]).with('WD_INSTALL_DIR').and_return('my_env_path')
79
+ expect(described_class.install_dir).to be('my_install_dir_path')
80
+ ensure
81
+ described_class.install_dir = nil
82
+ end
83
+ end
84
+ end
73
85
  end
74
86
  end
@@ -0,0 +1,17 @@
1
+ $downloadDevLink = "https://go.microsoft.com/fwlink/?linkid=2069324&Channel=Dev&language=en-us&Consent=0&IID=85213fc4-6a13-57ae-9082-72910982ede8"
2
+ $downloadCanaryLink = "https://go.microsoft.com/fwlink/?linkid=2084706&Channel=Canary&language=en-us&Consent=0&IID=85213fc4-6a13-57ae-9082-72910982ede8"
3
+ $devSetup = "C:\MicrosoftEdgeSetupDev.exe"
4
+ $canarySetup = "C:\MicrosoftEdgeSetupCanary.exe"
5
+
6
+ # Note: We're purposely skipping the -Wait flag in Start-Process.
7
+ # This is because Edge auto-launches after the setup is done and
8
+ # Start-Process continues to indefinitely wait on that process.
9
+ Write-Host "Installing Microsoft Edge (Dev)..." -ForegroundColor cyan
10
+ Invoke-WebRequest $downloadDevLink -OutFile $devSetup # Download Dev
11
+ Start-Process $devSetup # Run installer
12
+ Write-Host "Microsoft Edge (Dev) installed.`n" -ForegroundColor green
13
+
14
+ Write-Host "Installing Microsoft Edge (Canary)..." -ForegroundColor cyan
15
+ Invoke-WebRequest $downloadCanaryLink -OutFile $canarySetup # Download Canary
16
+ Start-Process $canarySetup # Run installer
17
+ Write-Host "Microsoft Edge (Canary) installed.`n" -ForegroundColor green