├── .gitignore
├── README.md
├── WebAPI.Testing.nuspec
├── WebAPI.Testing.sln
├── WebAPI.Testing.userprefs
├── licence.txt
├── packages.config
└── src
├── WebAPI.Testing.Tests
├── BrowserExtensionsFixture.cs
├── BrowserFixture.cs
├── EchoModel.cs
├── GetDataController.cs
├── JsonController.cs
├── Properties
│ └── AssemblyInfo.cs
├── ReusableBrowserFixture.cs
├── WebAPI.Testing.Tests.csproj
├── app.config
└── packages.config
└── WebAPI.Testing
├── Browser.cs
├── BrowserContext.cs
├── BrowserContextExtensions.cs
├── BrowserContextMultipartFormData.cs
├── BrowserExtensionMethods.cs
├── BrowserResponseBodyWrapperExtensions.cs
├── Fakes
└── FakeRootPathProvider.cs
├── IBrowserContextValues.cs
├── IHideObjectMembers.cs
├── Properties
└── AssemblyInfo.cs
├── ReusableBrowser.cs
├── WebAPI.Testing.csproj
├── app.config
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Rr]elease/
19 | x64/
20 | *_i.c
21 | *_p.c
22 | *.ilk
23 | *.meta
24 | *.obj
25 | *.pch
26 | *.pdb
27 | *.pgc
28 | *.pgd
29 | *.rsp
30 | *.sbr
31 | *.tlb
32 | *.tli
33 | *.tlh
34 | *.tmp
35 | *.log
36 | *.vspscc
37 | *.vssscc
38 | .builds
39 |
40 | # Visual C++ cache files
41 | ipch/
42 | *.aps
43 | *.ncb
44 | *.opensdf
45 | *.sdf
46 |
47 | # Visual Studio profiler
48 | *.psess
49 | *.vsp
50 | *.vspx
51 |
52 | # Guidance Automation Toolkit
53 | *.gpState
54 |
55 | # ReSharper is a .NET coding add-in
56 | _ReSharper*
57 |
58 | # NCrunch
59 | *.ncrunch*
60 | .*crunch*.local.xml
61 |
62 | # Installshield output folder
63 | [Ee]xpress
64 |
65 | # DocProject is a documentation generator add-in
66 | DocProject/buildhelp/
67 | DocProject/Help/*.HxT
68 | DocProject/Help/*.HxC
69 | DocProject/Help/*.hhc
70 | DocProject/Help/*.hhk
71 | DocProject/Help/*.hhp
72 | DocProject/Help/Html2
73 | DocProject/Help/html
74 |
75 | # Click-Once directory
76 | publish
77 |
78 | # Publish Web Output
79 | *.Publish.xml
80 |
81 | # NuGet Packages Directory
82 | packages
83 |
84 | # Windows Azure Build Output
85 | csx
86 | *.build.csdef
87 |
88 | # Windows Store app package directory
89 | AppPackages/
90 |
91 | # Others
92 | [Bb]in
93 | [Oo]bj
94 | sql
95 | TestResults
96 | [Tt]est[Rr]esult*
97 | *.Cache
98 | ClientBin
99 | [Ss]tyle[Cc]op.*
100 | ~$*
101 | *.dbmdl
102 | Generated_Code #added for RIA/Silverlight projects
103 |
104 | # Backup & report files from converting an old project file to a newer
105 | # Visual Studio version. Backup files are not needed, because we have git ;-)
106 | _UpgradeReport_Files/
107 | Backup*/
108 | UpgradeLog*.XML
109 | /WebAPI.Testing*.nupkg
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | WebAPI.Testing
2 | ==============
3 |
4 | Provides a way to test WebAPI projects.
5 |
6 | public class GetDataTests
7 | {
8 | [Fact]
9 | public void GetData_WhenRequested_ShouldReturnJSON()
10 | {
11 | var browser = new Browser();
12 | var response = browser.Get("/GetData", (with) =>
13 | {
14 | with.Header("Accept", "application/json");
15 | with.HttpRequest();
16 | });
17 |
18 | Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
19 | }
20 |
21 | [Fact]
22 | public void GetData_WhenRequested_ShouldReturnOKStatusCode()
23 | {
24 | var browser = new Browser();
25 | var response = browser.Get("/GetData", (with) =>
26 | {
27 | with.Header("Authorization", "Bearer johnsmith");
28 | with.Header("Accept", "application/json");
29 | with.HttpRequest();
30 | });
31 |
32 | Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
33 | }
34 | }
35 |
36 | This project is a modified version of [Nancy.Testing][1] but built to work with ASP.Net WebAPI
37 |
38 | [1]: https://github.com/NancyFx/Nancy/tree/master/src/Nancy.Testing
39 |
40 | ---
41 |
42 | To build nuget packages open a Developer Command Prompt and run: `buildandpack.cmd`
43 |
--------------------------------------------------------------------------------
/WebAPI.Testing.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WebAPI.Testing
5 | 2.0.$buildnumber$
6 | WebAPI.Testing
7 | Jonathan Channon, Dafydd Giddins
8 | Jonathan Channon, Dafydd Giddins
9 | https://github.com/jchannon/WebAPI.Testing/blob/master/licence.txt
10 | https://github.com/jchannon/WebAPI.Testing
11 | false
12 | Allows full pipeline testing for ASP.Net Web API
13 | Allows full pipeline testing for ASP.Net Web API
14 | Copyright © 2012
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/WebAPI.Testing.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAPI.Testing", "src\WebAPI.Testing\WebAPI.Testing.csproj", "{57EEDE70-EF3F-4DF9-9408-E08F272CDA00}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebAPI.Testing.Tests", "src\WebAPI.Testing.Tests\WebAPI.Testing.Tests.csproj", "{3D1B9E1B-034B-4CDB-85E2-224293699093}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2A87DE7D-2CDC-48F6-8388-FA56CF2B5BFF}"
11 | ProjectSection(SolutionItems) = preProject
12 | licence.txt = licence.txt
13 | README.md = README.md
14 | WebAPI.Testing.nuspec = WebAPI.Testing.nuspec
15 | EndProjectSection
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {3D1B9E1B-034B-4CDB-85E2-224293699093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {3D1B9E1B-034B-4CDB-85E2-224293699093}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {3D1B9E1B-034B-4CDB-85E2-224293699093}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {3D1B9E1B-034B-4CDB-85E2-224293699093}.Release|Any CPU.Build.0 = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(SolutionProperties) = preSolution
33 | HideSolutionNode = FALSE
34 | EndGlobalSection
35 | EndGlobal
36 |
--------------------------------------------------------------------------------
/WebAPI.Testing.userprefs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/licence.txt:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2012 Jonathan Channon and contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/BrowserExtensionsFixture.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | using System;
4 | using System.Net;
5 | using System.Web.Http;
6 | using Xunit;
7 | using RouteParameter = System.Web.Http.RouteParameter;
8 |
9 | public class BrowserExtensionsFixture
10 | {
11 | private readonly Browser _browser;
12 |
13 | public BrowserExtensionsFixture()
14 | {
15 | var config = new HttpConfiguration();
16 |
17 | config.Routes.MapHttpRoute(
18 | name: "ControllerAndActionfwefew",
19 | routeTemplate: "{controller}/{action}/{id}",
20 | defaults: new { id = RouteParameter.Optional }
21 | );
22 |
23 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
24 |
25 | _browser = new Browser(config);
26 | }
27 |
28 | [Fact]
29 | public void SouldBeAbleToPostJsonWithExtensions()
30 | {
31 | var response = _browser.PostAsJson("/json/post", new ADocument());
32 |
33 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
34 | }
35 |
36 | [Fact]
37 | public void PostingAsJsonCanStillSepcifyContextOptions()
38 | {
39 | string randomValue = Guid.NewGuid().ToString();
40 | var response = _browser.PostAsJson("/json/post", new ADocument(), with =>
41 | {
42 | with.Header("test", randomValue);
43 | });
44 |
45 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
46 | Assert.Equal(JsonController.TestHeaderValue, randomValue);
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/BrowserFixture.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Web;
9 | using System.Web.Http;
10 | using Xunit;
11 |
12 | public class BrowserFixture
13 | {
14 | private readonly Browser _browser;
15 |
16 | public BrowserFixture()
17 | {
18 | var config = new HttpConfiguration();
19 |
20 | config.Routes.MapHttpRoute(
21 | name: "ControllerAndActionfwefew",
22 | routeTemplate: "{controller}/{action}/{id}",
23 | defaults: new { id = RouteParameter.Optional }
24 | );
25 |
26 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
27 |
28 | _browser = new Browser(config);
29 | }
30 |
31 | [Fact]
32 | public void GetData_WhenRequested_ShouldReturnJSON()
33 | {
34 | var browser = new Browser();
35 | var response = browser.Get("/GetData/Get", (with) =>
36 | {
37 | with.Header("Accept", "application/json");
38 | with.HttpRequest();
39 | });
40 |
41 | Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
42 | }
43 |
44 | [Fact]
45 | public void Should_be_able_to_send_string_in_body()
46 | {
47 | const string thisIsMyRequestBody = "This is my request body";
48 |
49 | // When
50 | var result = _browser.Post("/GetData/WEE", with =>
51 | {
52 | with.HttpRequest();
53 | with.Body(thisIsMyRequestBody);
54 |
55 | });
56 |
57 | // Then
58 |
59 | Assert.Equal(thisIsMyRequestBody, result.Content.ReadAsStringAsync().Result);
60 | }
61 |
62 | [Fact]
63 | public void Should_be_able_to_set_user_host_address()
64 | {
65 | // Given
66 | const string userHostAddress = "127.0.0.1";
67 |
68 | // When
69 | var result = _browser.Get("/GetData/Get", with =>
70 | {
71 | with.HttpRequest();
72 | with.UserHostAddress(userHostAddress);
73 | });
74 |
75 | // Then
76 | Assert.Equal(userHostAddress, result.Content.ReadAsStringAsync().Result);
77 | }
78 |
79 | [Fact]
80 | public void Should_be_able_to_send_stream_in_body()
81 | {
82 | // Given
83 | const string thisIsMyRequestBody = "This is my request body";
84 | var stream = new MemoryStream();
85 | var writer = new StreamWriter(stream);
86 | writer.Write(thisIsMyRequestBody);
87 | writer.Flush();
88 | stream.Seek(0, SeekOrigin.Begin);
89 | // When
90 |
91 | var result = _browser.Post("/GetData/WEE", with =>
92 | {
93 | with.HttpRequest();
94 | with.Body(stream, "text/plain");
95 | });
96 |
97 | // Then
98 | Assert.Equal(thisIsMyRequestBody, result.Content.ReadAsStringAsync().Result);
99 | }
100 |
101 | [Fact]
102 | public void Should_be_able_to_send_json_in_body()
103 | {
104 | // Given
105 | var model = new EchoModel { SomeString = "Some String", SomeInt = 29, SomeBoolean = true };
106 |
107 | // When
108 | var result = _browser.Post("/GetData/WEE", with =>
109 | {
110 | with.JsonBody(model);
111 | });
112 |
113 |
114 | // Then
115 | var actualModel = result.Content.DeserializeJson();
116 |
117 | Assert.NotNull(actualModel);
118 | Assert.Equal(model.SomeString, actualModel.SomeString);
119 | Assert.Equal(model.SomeInt, actualModel.SomeInt);
120 | Assert.Equal(model.SomeBoolean, actualModel.SomeBoolean);
121 | }
122 |
123 | [Fact]
124 | public void Should_be_able_to_send_form_values()
125 | {
126 | var result = _browser.Post("/GetData/POO", with =>
127 | {
128 | with.FormValue("SomeString", "Some String");
129 | with.FormValue("SomeInt", "29");
130 | with.FormValue("SomeBoolean", "true");
131 | });
132 |
133 |
134 | var actualModel = result.Content.DeserializeJson();
135 |
136 | Assert.NotNull(actualModel);
137 | Assert.Equal("Some String", actualModel.SomeString);
138 | Assert.Equal(29, actualModel.SomeInt);
139 | Assert.Equal(true, actualModel.SomeBoolean);
140 | }
141 |
142 | [Fact]
143 | public void Should_add_basic_authentication_credentials_to_the_headers_of_the_request()
144 | {
145 | // Given
146 | var context = new BrowserContext();
147 |
148 | // When
149 | context.BasicAuth("username", "password");
150 |
151 | // Then
152 | IBrowserContextValues values = context;
153 |
154 | var credentials = string.Format("{0}:{1}", "username", "password");
155 | var encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
156 |
157 | Assert.Equal(1, values.Headers.Count);
158 | Assert.Equal("Basic " + encodedCredentials, values.Headers["Authorization"].First());
159 | }
160 |
161 | [Fact]
162 | public void Should_add_cookies_to_the_request()
163 | {
164 | // Given
165 | var context = new BrowserContext();
166 |
167 | var cookies =
168 | new Dictionary
169 | {
170 | {"CookieName", "CookieValue"},
171 | {"SomeCookieName", "SomeCookieValue"}
172 | };
173 |
174 | // When
175 | context.Cookie(cookies);
176 |
177 | // Then
178 | IBrowserContextValues values = context;
179 |
180 | var cookieString = cookies.Aggregate(string.Empty, (current, cookie) => current + string.Format("{0}={1};", HttpUtility.UrlEncode(cookie.Key), HttpUtility.UrlEncode(cookie.Value)));
181 |
182 | Assert.Equal(1, values.Headers["Cookie"].Count());
183 | Assert.Equal(cookieString, values.Headers["Cookie"].First());
184 |
185 | }
186 |
187 | [Fact]
188 | public void Should_add_cookie_to_the_request()
189 | {
190 | // Given
191 | var context = new BrowserContext();
192 |
193 | var cookies =
194 | new Dictionary
195 | {
196 | {"CookieName", "CookieValue"},
197 | {"SomeCookieName", "SomeCookieValue"}
198 | };
199 |
200 | // When
201 | foreach (var cookie in cookies)
202 | {
203 | context.Cookie(cookie.Key, cookie.Value);
204 | }
205 |
206 | // Then
207 | IBrowserContextValues values = context;
208 |
209 | var cookieString = cookies.Aggregate(string.Empty, (current, cookie) => current + string.Format("{0}={1};", HttpUtility.UrlEncode(cookie.Key), HttpUtility.UrlEncode(cookie.Value)));
210 |
211 | Assert.Equal(1, values.Headers["Cookie"].Count());
212 | Assert.Equal(cookieString, values.Headers["Cookie"].First());
213 |
214 | }
215 |
216 | [Fact]
217 | public void Should_add_cookies_to_the_request_and_get_cookies_in_response()
218 | {
219 | // Given
220 | var cookies =
221 | new Dictionary
222 | {
223 | {"CookieName", "CookieValue"},
224 | {"SomeCookieName", "SomeCookieValue"}
225 | };
226 |
227 | // When
228 | var result = _browser.Get("/GetData/Get/cookie", with =>
229 | {
230 | with.Cookie(cookies);
231 | });
232 |
233 | // Then
234 | var values = result.Headers.Single(x => x.Key == "Set-Cookie").Value.First().Split(';');
235 |
236 | Assert.Equal(2, values.Count());
237 |
238 | Assert.Equal(cookies.First().Key, values[0].Substring(0, values[0].IndexOf("=")));
239 | Assert.Equal(cookies.First().Value, values[0].Substring(values[0].IndexOf("=") + 1));
240 |
241 | Assert.Equal(cookies.Last().Key, values[1].Substring(0, values[1].IndexOf("=")).Trim()); //Have to trim as they are seperated by a whitespace
242 | Assert.Equal(cookies.Last().Value, values[1].Substring(values[1].IndexOf("=") + 1).Trim());
243 |
244 | }
245 |
246 | [Fact]
247 | public void Should_add_a_cookie_to_the_request_and_get_a_cookie_in_response()
248 | {
249 | // Given, When
250 | var result = _browser.Get("/GetData/Get/cookie", with => with.Cookie("CookieName", "CookieValue"));
251 |
252 | // Then
253 |
254 | var values = result.Headers.Single(x => x.Key == "Set-Cookie").Value.First().Split(';');
255 |
256 | Assert.Equal(1, values.Count());
257 | Assert.Equal("CookieName", values[0].Substring(0, values[0].IndexOf("=")));
258 | Assert.Equal("CookieValue", values[0].Substring(values[0].IndexOf("=") + 1));
259 | }
260 |
261 | //[Fact]
262 | //public void Should_be_able_to_continue_with_another_request()
263 | //{
264 | // // Given
265 | // const string FirstRequestBody = "This is my first request body";
266 | // const string SecondRequestBody = "This is my second request body";
267 | // var firstRequestStream = new MemoryStream();
268 | // var firstRequestWriter = new StreamWriter(firstRequestStream);
269 | // firstRequestWriter.Write(FirstRequestBody);
270 | // firstRequestWriter.Flush();
271 | // var secondRequestStream = new MemoryStream();
272 | // var secondRequestWriter = new StreamWriter(secondRequestStream);
273 | // secondRequestWriter.Write(SecondRequestBody);
274 | // secondRequestWriter.Flush();
275 |
276 | // // When
277 | // var result = browser.Post("/", with =>
278 | // {
279 | // with.HttpRequest();
280 | // with.Body(firstRequestStream, "text/plain");
281 | // }).Then.Post("/", with =>
282 | // {
283 | // with.HttpRequest();
284 | // with.Body(secondRequestStream, "text/plain");
285 | // });
286 |
287 | // // Then
288 | // result.Body.AsString().ShouldEqual(SecondRequestBody);
289 | //}
290 |
291 | // [Fact]
292 | // public void Should_maintain_cookies_when_chaining_requests()
293 | // {
294 | // // Given
295 | // // When
296 | // var result = browser.Get(
297 | // "/session",
298 | // with => with.HttpRequest())
299 | // .Then
300 | // .Get(
301 | // "/session",
302 | // with => with.HttpRequest());
303 |
304 | // result.Body.AsString().ShouldEqual("Current session value is: I've created a session!");
305 | // }
306 |
307 | // [Fact]
308 | // public void Should_maintain_cookies_even_if_not_set_on_directly_preceding_request()
309 | // {
310 | // // Given
311 | // // When
312 | // var result = browser.Get(
313 | // "/session",
314 | // with => with.HttpRequest())
315 | // .Then
316 | // .Get(
317 | // "/nothing",
318 | // with => with.HttpRequest())
319 | // .Then
320 | // .Get(
321 | // "/session",
322 | // with => with.HttpRequest());
323 |
324 | // result.Body.AsString().ShouldEqual("Current session value is: I've created a session!");
325 | // }
326 |
327 | [Fact]
328 | public void Should_be_able_to_not_specify_delegate_for_basic_http_request()
329 | {
330 | var result = _browser.Get("/GetData/Get/scheme");
331 |
332 | Assert.Equal("http", result.Content.ReadAsStringAsync().Result);
333 | }
334 |
335 | [Fact]
336 | public void Should_add_ajax_header()
337 | {
338 | var result = _browser.Get("/GetData/Get/ajax", with => with.AjaxRequest());
339 |
340 | Assert.Equal("ajax", result.Content.ReadAsStringAsync().Result);
341 | }
342 |
343 | // [Fact]
344 | // public void Should_add_forms_authentication_cookie_to_the_request()
345 | // {
346 | // var userId = A.Dummy();
347 |
348 | // var formsAuthConfig = new FormsAuthenticationConfiguration()
349 | // {
350 | // RedirectUrl = "/login",
351 | // UserMapper = A.Fake(),
352 | // };
353 |
354 | // var encryptedId = formsAuthConfig.CryptographyConfiguration.EncryptionProvider.Encrypt(userId.ToString());
355 | // var hmacBytes = formsAuthConfig.CryptographyConfiguration.HmacProvider.GenerateHmac(encryptedId);
356 | // var hmacString = Convert.ToBase64String(hmacBytes);
357 | // var cookieContents = String.Format("{1}{0}", encryptedId, hmacString);
358 |
359 | // var response = browser.Get("/cookie", (with) =>
360 | // {
361 | // with.HttpRequest();
362 | // with.FormsAuth(userId, formsAuthConfig);
363 | // });
364 |
365 | // var cookie = response.Cookies.Single(c => c.Name == FormsAuthentication.FormsAuthenticationCookieName);
366 | // var cookieValue = HttpUtility.UrlDecode(cookie.Value);
367 | // cookieValue.ShouldEqual(cookieContents);
368 | // }
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/EchoModel.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | public class EchoModel
4 | {
5 | public string SomeString { get; set; }
6 | public int SomeInt { get; set; }
7 | public bool SomeBoolean { get; set; }
8 | }
9 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/GetDataController.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | using System.IO;
4 | using System.Net.Http;
5 | using System.Web.Http;
6 |
7 | public class GetDataController : ApiController
8 | {
9 | [ActionName("WEE")]
10 | public HttpResponseMessage Post()
11 | {
12 | var body = new StreamReader(Request.Content.ReadAsStreamAsync().Result).ReadToEnd();
13 |
14 |
15 | Stream stream = new MemoryStream();
16 | var writer = new StreamWriter(stream);
17 | writer.Write(body);
18 | writer.Flush();
19 | stream.Seek(0, SeekOrigin.Begin);
20 |
21 | return new HttpResponseMessage
22 | {
23 |
24 | Content = new StreamContent(stream)
25 | };
26 | }
27 |
28 | [ActionName("POO")]
29 | public EchoModel PostBinderTHISISSHIT(EchoModel echoModel)
30 | {
31 |
32 | return echoModel;
33 | }
34 |
35 | public HttpResponseMessage Get()
36 | {
37 | //I would return return Request.RequestUri.Host; but by default API wont return text/plain
38 |
39 | return new HttpResponseMessage() { Content = new StringContent(Request.RequestUri.Host) };
40 | }
41 |
42 | public HttpResponseMessage Get(string id)
43 | {
44 | switch (id)
45 | {
46 | case "scheme":
47 | return new HttpResponseMessage() { Content = new StringContent(Request.RequestUri.Scheme.ToLower()) };
48 | break;
49 | case "cookie":
50 | var response = new HttpResponseMessage() { Content = new StringContent("Cookies") };
51 |
52 | response.Headers.AddCookies(Request.Headers.GetCookies());
53 |
54 | return response;
55 |
56 | break;
57 | case "ajax":
58 |
59 | return new HttpResponseMessage()
60 | {
61 | Content =
62 | new StringContent(this.Request.Headers.Contains("X-Requested-With") ? "ajax" : "not-ajax")
63 | };
64 | break;
65 | default:
66 | return new HttpResponseMessage() { Content = new StringContent("Stupid WebAPI doesnt allow more than one Get hence this monstrosity") };
67 | break;
68 | }
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/JsonController.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Net.Http;
7 | using System.Web.Http;
8 |
9 | public class JsonController : ApiController
10 | {
11 | public HttpResponseMessage Post(ADocument documentToStore)
12 | {
13 | if (Request.Headers.Contains("test"))
14 | {
15 | var testHeaderValues = Request.Headers.GetValues("test");
16 | TestHeaderValue = testHeaderValues.First();
17 | }
18 |
19 | return new HttpResponseMessage(HttpStatusCode.OK);
20 | }
21 |
22 | public static string TestHeaderValue { get; private set; }
23 | }
24 |
25 | public class ADocument
26 | {
27 | public string Name { get; set; }
28 | public Dictionary ChapterIndex { get; set; }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebAPI.Testing.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebAPI.Testing.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3d1b9e1b-034b-4cdb-85e2-224293699093")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/ReusableBrowserFixture.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing.Tests
2 | {
3 | using System.Net;
4 | using System.Web.Http;
5 | using Xunit;
6 |
7 | public class ReusableBrowserFixture
8 | {
9 | private readonly ReusableBrowser _browser;
10 |
11 | public ReusableBrowserFixture()
12 | {
13 | var config = new HttpConfiguration();
14 |
15 | config.Routes.MapHttpRoute(
16 | name: "ControllerAndActionfwefew",
17 | routeTemplate: "{controller}/{action}/{id}",
18 | defaults: new { id = RouteParameter.Optional }
19 | );
20 |
21 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
22 |
23 | _browser = new ReusableBrowser(config);
24 | }
25 |
26 | [Fact]
27 | public void Can_Send_MultipleRequests_ToSingle_Instance()
28 | {
29 | var response = _browser.Get("/GetData/Get", (with) =>
30 | {
31 | with.Header("Accept", "application/json");
32 | with.HttpRequest();
33 | });
34 |
35 | Assert.Equal(response.StatusCode, HttpStatusCode.OK);
36 |
37 | var secondResponse = _browser.Get("/GetData/Get", (with) =>
38 | {
39 | with.Header("Accept", "application/json");
40 | with.HttpRequest();
41 | });
42 |
43 | Assert.Equal(secondResponse.StatusCode, HttpStatusCode.OK);
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/WebAPI.Testing.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3D1B9E1B-034B-4CDB-85E2-224293699093}
8 | Library
9 | Properties
10 | WebAPI.Testing.Tests
11 | WebAPI.Testing.Tests
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
36 | True
37 |
38 |
39 |
40 |
41 | ..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
42 | True
43 |
44 |
45 |
46 | ..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
47 | True
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | ..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
57 | True
58 |
59 |
60 | ..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll
61 | True
62 |
63 |
64 | ..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll
65 | True
66 |
67 |
68 | ..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll
69 | True
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}
88 | WebAPI.Testing
89 |
90 |
91 |
92 |
99 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/Browser.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Net.Http;
8 | using System.Text;
9 | using System.Web;
10 | using System.Web.Http;
11 | using RouteParameter = System.Web.Http.RouteParameter;
12 |
13 | ///
14 | /// Provides the capability of executing a request with WebAPI, using a specific configuration provided by an instance.
15 | ///
16 | public class Browser : IHideObjectMembers, IDisposable
17 | {
18 | private readonly bool _disposeServerAfterRequest;
19 | private readonly HttpServer _server;
20 |
21 | private readonly IDictionary cookies = new Dictionary();
22 |
23 | public HttpClient BrowserHttpClient { get; set; }
24 |
25 | public Browser(bool disposeServerAfterRequest = true)
26 | {
27 | _disposeServerAfterRequest = disposeServerAfterRequest;
28 | var config = new HttpConfiguration();
29 | config.Routes.MapHttpRoute(name: "Default", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional });
30 | config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
31 | _server = new HttpServer(config);
32 | }
33 |
34 | public Browser(HttpConfiguration httpConfiguration, bool disposeServerAfterRequest = true)
35 | {
36 | _disposeServerAfterRequest = disposeServerAfterRequest;
37 | HttpConfiguration config = httpConfiguration;
38 | _server = new HttpServer(config);
39 | }
40 |
41 | ///
42 | /// Performs a DELETE requests against WebAPI.
43 | ///
44 | /// The path that is being requested.
45 | /// An closure for providing browser context for the request.
46 | /// An instance of the executed request.
47 | public HttpResponseMessage Delete(string path, Action browserContext = null)
48 | {
49 | return this.HandleRequest(HttpMethod.Delete, path, browserContext);
50 | }
51 |
52 | ///
53 | /// Performs a GET requests against WebAPI.
54 | ///
55 | /// The path that is being requested.
56 | /// An closure for providing browser context for the request.
57 | /// An instance of the executed request.
58 | public HttpResponseMessage Get(string path, Action browserContext = null)
59 | {
60 | return this.HandleRequest(HttpMethod.Get, path, browserContext);
61 | }
62 |
63 | ///
64 | /// Performs a HEAD requests against WebAPI.
65 | ///
66 | /// The path that is being requested.
67 | /// An closure for providing browser context for the request.
68 | /// An instance of the executed request.
69 | public HttpResponseMessage Head(string path, Action browserContext = null)
70 | {
71 | return this.HandleRequest(HttpMethod.Head, path, browserContext);
72 | }
73 |
74 | ///
75 | /// Performs a OPTIONS requests against WebAPI.
76 | ///
77 | /// The path that is being requested.
78 | /// An closure for providing browser context for the request.
79 | /// An instance of the executed request.
80 | public HttpResponseMessage Options(string path, Action browserContext = null)
81 | {
82 | return this.HandleRequest(HttpMethod.Options, path, browserContext);
83 | }
84 |
85 | /////
86 | ///// Performs a PATCH requests against WebAPI.
87 | /////
88 | ///// The path that is being requested.
89 | ///// An closure for providing browser context for the request.
90 | ///// An instance of the executed request.
91 | //public HttpResponseMessage Patch(string path, Action browserContext = null)
92 | //{
93 | // return this.HandleRequest(HttpMethod., path, browserContext);
94 | //}
95 |
96 | ///
97 | /// Performs a POST requests against WebAPI.
98 | ///
99 | /// The path that is being requested.
100 | /// An closure for providing browser context for the request.
101 | /// An instance of the executed request.
102 | public HttpResponseMessage Post(string path, Action browserContext = null)
103 | {
104 | return this.HandleRequest(HttpMethod.Post, path, browserContext);
105 | }
106 |
107 | ///
108 | /// Performs a PUT requests against WebAPI.
109 | ///
110 | /// The path that is being requested.
111 | /// An closure for providing browser context for the request.
112 | /// An instance of the executed request.
113 | public HttpResponseMessage Put(string path, Action browserContext = null)
114 | {
115 | return this.HandleRequest(HttpMethod.Put, path, browserContext);
116 | }
117 |
118 | ///
119 | /// Performs a PATCH requests against WebAPI.
120 | ///
121 | /// The path that is being requested.
122 | /// An closure for providing browser context for the request.
123 | /// An instance of the executed request.
124 | public HttpResponseMessage Patch(string path, Action browserContext = null)
125 | {
126 | return this.HandleRequest(new HttpMethod("PATCH"), path, browserContext);
127 | }
128 |
129 | ///
130 | /// Performs a TRACE requests against WebAPI.
131 | ///
132 | /// The path that is being requested.
133 | /// An closure for providing browser context for the request.
134 | /// An instance of the executed request.
135 | public HttpResponseMessage Trace(string path, Action browserContext = null)
136 | {
137 | return this.HandleRequest(HttpMethod.Trace, path, browserContext);
138 | }
139 |
140 | private HttpResponseMessage HandleRequest(HttpMethod method, string path, Action browserContext)
141 | {
142 | var request =
143 | CreateRequest(method, path, browserContext ?? this.DefaultBrowserContext);
144 |
145 | if (BrowserHttpClient == null)
146 | BrowserHttpClient = new HttpClient(_server);
147 |
148 | HttpResponseMessage response = BrowserHttpClient.SendAsync(request).Result;
149 |
150 | request.Dispose();
151 |
152 | if (_disposeServerAfterRequest && _server != null)
153 | {
154 | _server.Dispose();
155 | }
156 |
157 | return response;
158 | }
159 |
160 | private void DefaultBrowserContext(BrowserContext context)
161 | {
162 | context.HttpRequest();
163 | }
164 |
165 | private void SetCookies(BrowserContext context)
166 | {
167 | if (!this.cookies.Any())
168 | {
169 | return;
170 | }
171 |
172 | var cookieString = this.cookies.Aggregate(string.Empty, (current, cookie) => current + string.Format("{0}={1};", HttpUtility.UrlEncode(cookie.Key), HttpUtility.UrlEncode(cookie.Value)));
173 |
174 | context.Header("Cookie", cookieString);
175 | }
176 |
177 | private static void BuildRequestBody(IBrowserContextValues contextValues)
178 | {
179 | if (contextValues.Body != null)
180 | {
181 | return;
182 | }
183 |
184 | var useFormValues = !String.IsNullOrEmpty(contextValues.FormValues);
185 | var bodyContents = useFormValues ? contextValues.FormValues : contextValues.BodyString;
186 | var bodyBytes = bodyContents != null ? Encoding.UTF8.GetBytes(bodyContents) : new byte[] { };
187 |
188 | if (useFormValues && !contextValues.Headers.ContainsKey("Content-Type"))
189 | {
190 | contextValues.Headers["Content-Type"] = new[] { "application/x-www-form-urlencoded" };
191 | }
192 |
193 | contextValues.Body = new MemoryStream(bodyBytes);
194 | }
195 |
196 | private HttpRequestMessage CreateRequest(HttpMethod method, string path, Action browserContext)
197 | {
198 | var context = new BrowserContext();
199 |
200 | this.SetCookies(context);
201 |
202 | browserContext.Invoke(context);
203 |
204 | var contextValues =
205 | (IBrowserContextValues)context;
206 |
207 | BuildRequestBody(contextValues);
208 |
209 | var request = new HttpRequestMessage();
210 | request.Method = method;
211 | request.RequestUri = new Uri(contextValues.Protocol + "://" + contextValues.UserHostAddress + path + contextValues.QueryString);
212 |
213 | request.Content = new StreamContent(contextValues.Body);
214 |
215 | foreach (var header in contextValues.Headers)
216 | {
217 |
218 | if (header.Key.StartsWith("Content") && !request.Content.Headers.Contains(header.Key))
219 | {
220 | request.Content.Headers.Add(header.Key, header.Value);
221 | }
222 | else if (!header.Key.StartsWith("Content") && !request.Headers.Contains(header.Key))
223 | {
224 | request.Headers.Add(header.Key, header.Value);
225 | }
226 | }
227 |
228 | return request;
229 | }
230 |
231 | public void Dispose()
232 | {
233 | if (_server != null)
234 | {
235 | _server.Dispose();
236 | }
237 | }
238 | }
239 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/BrowserContext.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 |
7 | ///
8 | /// Defines the context that a instance should run under.
9 | ///
10 | public class BrowserContext : IBrowserContextValues
11 | {
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | public BrowserContext()
16 | {
17 | this.Values.Headers = new Dictionary>();
18 | this.Values.Protocol = "http";
19 | this.Values.QueryString = String.Empty;
20 | this.Values.BodyString = String.Empty;
21 | this.Values.FormValues = String.Empty;
22 | UserHostAddress("localhost");
23 | }
24 |
25 | ///
26 | /// Gets or sets the that should be sent with the HTTP request.
27 | ///
28 | /// A that contains the body that should be sent with the HTTP request.
29 | Stream IBrowserContextValues.Body { get; set; }
30 |
31 | ///
32 | /// Gets or sets the protocol that should be sent with the HTTP request.
33 | ///
34 | /// A contains the the protocol that should be sent with the HTTP request..
35 | string IBrowserContextValues.Protocol { get; set; }
36 |
37 | ///
38 | /// Gets or sets the querystring
39 | ///
40 | string IBrowserContextValues.QueryString { get; set; }
41 |
42 | ///
43 | /// Gets or sets the user host address
44 | ///
45 | string IBrowserContextValues.UserHostAddress { get; set; }
46 |
47 | ///
48 | /// Gets or sets the body string
49 | ///
50 | string IBrowserContextValues.BodyString { get; set; }
51 |
52 | ///
53 | /// Gets or sets the form values string
54 | ///
55 | string IBrowserContextValues.FormValues { get; set; }
56 |
57 | ///
58 | /// Gets or sets the headers that should be sent with the HTTP request.
59 | ///
60 | /// An instance that contains the headers that should be sent with the HTTP request.
61 | IDictionary> IBrowserContextValues.Headers { get; set; }
62 |
63 | ///
64 | /// Adds a body to the HTTP request.
65 | ///
66 | /// A string that should be used as the HTTP request body.
67 | public void Body(string body)
68 | {
69 | this.Values.BodyString = body;
70 | }
71 |
72 | ///
73 | /// Adds a body to the HTTP request.
74 | ///
75 | /// A stream that should be used as the HTTP request body.
76 | /// Content type of the HTTP request body. Defaults to 'application/octet-stream'
77 | public void Body(Stream body, string contentType = null)
78 | {
79 | this.Values.Body = body;
80 | this.Header("Content-Type", contentType ?? "application/octet-stream");
81 | }
82 |
83 | ///
84 | /// Adds an application/x-www-form-urlencoded form value.
85 | ///
86 | /// The name of the form element.
87 | /// The value of the form element.
88 | public void FormValue(string key, string value)
89 | {
90 | if (!String.IsNullOrEmpty(this.Values.BodyString))
91 | {
92 | throw new InvalidOperationException("Form value cannot be set as well as body string");
93 | }
94 |
95 | this.Values.FormValues += String.Format(
96 | "{0}{1}={2}",
97 | this.Values.FormValues.Length == 0 ? String.Empty : "&",
98 | key,
99 | value);
100 | }
101 |
102 | ///
103 | /// Adds a header to the HTTP request.
104 | ///
105 | /// The name of the header.
106 | /// The value of the header.
107 | public void Header(string name, string value)
108 | {
109 | if (!this.Values.Headers.ContainsKey(name))
110 | {
111 | this.Values.Headers.Add(name, new List());
112 | }
113 |
114 | var values = (List)this.Values.Headers[name];
115 | values.Add(value);
116 |
117 | this.Values.Headers[name] = values;
118 | }
119 |
120 | ///
121 | /// Configures the request to be sent over HTTP.
122 | ///
123 | public void HttpRequest()
124 | {
125 | this.Values.Protocol = "http";
126 | }
127 |
128 | ///
129 | /// Configures the request to be sent over HTTPS.
130 | ///
131 | public void HttpsRequest()
132 | {
133 | this.Values.Protocol = "https";
134 | }
135 |
136 | ///
137 | /// Adds a query string entry
138 | ///
139 | public void Query(string key, string value)
140 | {
141 | this.Values.QueryString += String.Format(
142 | "{0}{1}={2}",
143 | this.Values.QueryString.Length == 0 ? "?" : "&",
144 | key,
145 | value);
146 | }
147 |
148 | ///
149 | /// Sets the user host address.
150 | ///
151 | public void UserHostAddress(string userHostAddress)
152 | {
153 | this.Values.UserHostAddress = userHostAddress;
154 | }
155 |
156 | private IBrowserContextValues Values
157 | {
158 | get { return this; }
159 | }
160 | }
161 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/BrowserContextExtensions.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Web;
3 | using Newtonsoft.Json;
4 |
5 | namespace WebAPI.Testing
6 | {
7 | using System;
8 | using System.Globalization;
9 | using System.Text;
10 | using System.IO;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 |
14 | //using Nancy.Authentication.Forms;
15 | //using Nancy.Extensions;
16 | //using Nancy.Helpers;
17 | //using Nancy.Responses;
18 | //using Responses.Negotiation;
19 |
20 | ///
21 | /// Defines extensions for the type.
22 | ///
23 | public static class BrowserContextExtensions
24 | {
25 | ///
26 | /// Adds a multipart/form-data encoded request body to the , using the default boundary name.
27 | ///
28 | /// The that the data should be added to.
29 | /// The multipart/form-data encoded data that should be added.
30 | public static void MultiPartFormData(this BrowserContext browserContext, BrowserContextMultipartFormData multipartFormData)
31 | {
32 | MultiPartFormData(browserContext, multipartFormData, BrowserContextMultipartFormData.DefaultBoundaryName);
33 | }
34 |
35 | ///
36 | /// Adds a multipart/form-data encoded request body to the .
37 | ///
38 | /// The that the data should be added to.
39 | /// The multipart/form-data encoded data that should be added.
40 | /// The name of the boundary to be used
41 | public static void MultiPartFormData(this BrowserContext browserContext, BrowserContextMultipartFormData multipartFormData, string boundaryName)
42 | {
43 | var contextValues =
44 | (IBrowserContextValues)browserContext;
45 |
46 | contextValues.Body = multipartFormData.Body;
47 | contextValues.Headers["Content-Type"] = new[] { "multipart/form-data; boundary=" + boundaryName };
48 | }
49 |
50 | ///
51 | /// Adds a application/json request body to the .
52 | ///
53 | /// The that the data should be added to.
54 | /// The model to be serialized to json.
55 | /// Optionally opt in to using a different JSON serializer.
56 | public static void JsonBody(this BrowserContext browserContext, TModel model/*, ISerializer serializer = null*/)
57 | {
58 | //if (serializer == null)
59 | //{
60 | // serializer = new JsonSerializer();
61 | //}
62 |
63 | var serializer = new JsonSerializer();
64 |
65 | var contextValues =
66 | (IBrowserContextValues)browserContext;
67 |
68 | contextValues.Body = new MemoryStream();
69 |
70 | using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(contextValues.Body, UTF8Encoding.UTF8)) { CloseOutput = false })
71 | {
72 | serializer.Serialize(jsonTextWriter, model);
73 | jsonTextWriter.Flush();
74 | contextValues.Body.Seek(0, SeekOrigin.Begin);
75 | }
76 |
77 | //serializer.Serialize("application/json", model, contextValues.Body);
78 | browserContext.Header("Content-Type", "application/json");
79 | }
80 |
81 | ///
82 | /// Adds basic authorization credentials to the headers of the .
83 | ///
84 | /// The that the data should be added to.
85 | /// The username to be encoded.
86 | /// The password to be encoded.
87 | public static void BasicAuth(this BrowserContext browserContext, string username, string password)
88 | {
89 | var credentials = string.Format("{0}:{1}", username, password);
90 |
91 | var encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
92 |
93 | browserContext.Header("Authorization", "Basic " + encodedCredentials);
94 | }
95 |
96 | ///
97 | /// Adds a cookie to the headers of the .
98 | ///
99 | /// The that the data should be added to.
100 | /// The collection of cookies to add to the cookie request header.
101 | public static void Cookie(this BrowserContext browserContext, IDictionary cookies)
102 | {
103 | if (!cookies.Any())
104 | {
105 | return;
106 | }
107 |
108 | foreach (var cookie in cookies)
109 | {
110 | browserContext.Cookie(cookie.Key, cookie.Value);
111 | }
112 | }
113 |
114 | ///
115 | /// Adds a cookie to the headers of the .
116 | ///
117 | /// The that the data should be added to.
118 | /// The name of the cookie.
119 | /// The value of the cookie.
120 | public static void Cookie(this BrowserContext browserContext, string key, string value)
121 | {
122 | var contextValues =
123 | (IBrowserContextValues)browserContext;
124 |
125 | if (!contextValues.Headers.ContainsKey("Cookie"))
126 | {
127 | contextValues.Headers.Add("Cookie", new List { string.Empty });
128 | }
129 |
130 | var values = (List)contextValues.Headers["Cookie"];
131 | values[0] += string.Format("{0}={1};", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value));
132 | }
133 |
134 | ///
135 | /// Adds a header to indicate this request is an "ajax request"
136 | ///
137 | ///
138 | /// The that the data should be added to.
139 | public static void AjaxRequest(this BrowserContext browserContext)
140 | {
141 | browserContext.Header("X-Requested-With", "XMLHttpRequest");
142 | }
143 |
144 | /////
145 | ///// Adds forms authentication cookie to the headers of the .
146 | /////
147 | ///// The that the data should be added to.
148 | ///// The user identifier
149 | ///// Current configuration.
150 | //public static void FormsAuth(this BrowserContext browserContext, Guid userId, FormsAuthenticationConfiguration formsAuthenticationConfiguration)
151 | //{
152 | // var encryptedId = formsAuthenticationConfiguration.CryptographyConfiguration.EncryptionProvider.Encrypt(userId.ToString());
153 |
154 | // var hmacBytes = formsAuthenticationConfiguration.CryptographyConfiguration.HmacProvider.GenerateHmac(encryptedId);
155 |
156 | // var hmacString = Convert.ToBase64String(hmacBytes);
157 |
158 | // var cookieContents = String.Format("{1}{0}", encryptedId, hmacString);
159 |
160 | // Cookie(browserContext, FormsAuthentication.FormsAuthenticationCookieName, cookieContents);
161 | //}
162 |
163 | //public static void Accept(this BrowserContext browserContext, MediaRange mediaRange)
164 | //{
165 | // browserContext.Accept(mediaRange, 1.0m);
166 | //}
167 |
168 | //public static void Accept(this BrowserContext browserContext, MediaRange mediaRange, decimal quality)
169 | //{
170 | // var contextValues =
171 | // (IBrowserContextValues)browserContext;
172 |
173 | // if (contextValues.Headers.ContainsKey("accept"))
174 | // {
175 | // if (contextValues.Headers["accept"].Count().Equals(1))
176 | // {
177 | // if (contextValues.Headers["accept"].Any(x => x.Equals("*/*")))
178 | // {
179 | // contextValues.Headers.Remove("accept");
180 | // }
181 | // }
182 | // }
183 |
184 | // var mediaTypeWithQuality =
185 | // string.Concat(mediaRange, ";q=", Convert.ToString(quality, CultureInfo.InvariantCulture));
186 |
187 | // browserContext.Header("accept", mediaTypeWithQuality);
188 | //}
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/BrowserContextMultipartFormData.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Text;
6 |
7 | ///
8 | /// Contains the functionality for setting up a multipart/form-data encoded request body that should be used by an instance.
9 | ///
10 | public class BrowserContextMultipartFormData
11 | {
12 | public const string DefaultBoundaryName = "--NancyMultiPartBoundary123124";
13 |
14 | private readonly string boundaryName;
15 | ///
16 | /// Initializes a new instance of the class using the default boundary name
17 | ///
18 | /// The configuration that should be used to create the multipart/form-data encoded data.
19 | public BrowserContextMultipartFormData(Action configuration)
20 | : this(configuration, DefaultBoundaryName)
21 | {
22 | }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | /// The configuration that should be used to create the multipart/form-data encoded data.
28 | /// Boundary name to be used
29 | public BrowserContextMultipartFormData(Action configuration, string boundaryName)
30 | {
31 | this.boundaryName = boundaryName;
32 | this.Body = new MemoryStream();
33 |
34 | var configurator =
35 | new BrowserContextMultipartFormDataConfigurator(this.Body, boundaryName);
36 |
37 | configuration.Invoke(configurator);
38 | this.TerminateBoundary();
39 | this.Body.Position = 0;
40 | }
41 |
42 | ///
43 | /// Gets the that should be used by the HTTP request to pass in the multipart/form-data encoded values.
44 | ///
45 | /// A that contains the multipart/form-data encoded values.
46 | public Stream Body { get; private set; }
47 |
48 | private void TerminateBoundary()
49 | {
50 | var endBoundary = String.Format("\r\n--{0}--\r\n", this.boundaryName);
51 |
52 | var encodedHeaders =
53 | Encoding.ASCII.GetBytes(endBoundary);
54 |
55 | this.Body.Write(encodedHeaders, 0, encodedHeaders.Length);
56 | }
57 |
58 | ///
59 | /// Provides an API for configuring a multipart/form-data encoded request body.
60 | ///
61 | public class BrowserContextMultipartFormDataConfigurator
62 | {
63 | private const string CRLF = "\r\n";
64 | private readonly Stream body;
65 | private readonly string boundary;
66 |
67 | ///
68 | /// Initializes a new instance of the class.
69 | ///
70 | /// The that the values should be written to.
71 | /// The multipart/form-data boundary that should be used in the request body.
72 | public BrowserContextMultipartFormDataConfigurator(Stream body, string boundary)
73 | {
74 | this.body = body;
75 | this.boundary = boundary;
76 | }
77 |
78 | ///
79 | /// Adds a file to the request body.
80 | ///
81 | /// The name of the file http element that was used to upload the file.
82 | /// Name of the file.
83 | /// The mime type of file.
84 | /// The content of the file
85 | public void AddFile(string name, string fileName, string contentType, Stream file)
86 | {
87 | this.AddFieldHeaders(name, contentType, fileName);
88 | this.AddContent(file);
89 | }
90 |
91 | public void AddFormField(string name, string contentType, string data)
92 | {
93 | this.AddFormField(name, contentType, new MemoryStream(Encoding.ASCII.GetBytes(data)));
94 | }
95 |
96 | public void AddFormField(string name, string contentType, Stream data)
97 | {
98 | this.AddFieldHeaders(name, contentType);
99 | this.AddContent(data);
100 | }
101 |
102 | private void AddContent(Stream data)
103 | {
104 | data.Position = 0;
105 | data.CopyTo(this.body);
106 | }
107 |
108 | private void AddFieldHeaders(string name, string contentType, string filename = null)
109 | {
110 | var builder = new StringBuilder();
111 |
112 | builder.Append(CRLF);
113 | builder.Append("--" + this.boundary);
114 | builder.Append(CRLF);
115 | builder.AppendFormat(@"Content-Disposition: form-data; name=""{0}""", name);
116 | if (!String.IsNullOrWhiteSpace(filename))
117 | {
118 | builder.AppendFormat(@"; filename=""{0}""", filename);
119 | }
120 | builder.Append(CRLF);
121 | builder.AppendFormat(@"Content-Type: {0}", contentType);
122 | builder.Append(CRLF);
123 | builder.Append(CRLF);
124 |
125 | var encodedHeaders =
126 | Encoding.ASCII.GetBytes(builder.ToString());
127 |
128 | this.body.Write(encodedHeaders, 0, encodedHeaders.Length);
129 | }
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/BrowserExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System;
4 | using System.Net.Http;
5 | using Newtonsoft.Json;
6 |
7 | public static class BrowserExtensions
8 | {
9 | public static HttpResponseMessage PostAsJson(this Browser @this, string path, object body,
10 | Action browserContext = null)
11 | {
12 | var jsonBody = JsonConvert.SerializeObject(body);
13 | HttpResponseMessage result = @this.Post(path, with =>
14 | {
15 | with.HttpRequest();
16 | with.Body(jsonBody);
17 | with.Header("Content-Type", "application/json");
18 | if (browserContext != null)
19 | browserContext(with);
20 | });
21 | return result;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/BrowserResponseBodyWrapperExtensions.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace WebAPI.Testing
4 | {
5 | using System;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Xml;
10 | using System.Xml.Serialization;
11 | using System.Net.Http;
12 | using Newtonsoft.Json;
13 |
14 |
15 | ///
16 | /// Extension method for formatting the contents of a .
17 | ///
18 | public static class BrowserResponseBodyWrapperExtensions
19 | {
20 | ///
21 | /// Gets the HTTP response body wrapped in a .
22 | ///
23 | /// An instance of the that the extension should be invoked on.
24 | /// A representation of the HTTP response body.
25 | //public static Stream AsStream(this HttpResponseMessage bodyWrapper)
26 | //{
27 | // return new MemoryStream(bodyWrapper.Content.ReadAsByteArrayAsync().Result);
28 | //}
29 |
30 | /////
31 | ///// Gets the HTTP response body wrapped in a string.
32 | /////
33 | ///// An instance of the that the extension should be invoked on.
34 | ///// A string containing the HTTP response body.
35 | //public static string AsString(this HttpResponseMessage bodyWrapper)
36 | //{
37 | // return Encoding.UTF8.GetString(bodyWrapper.Content.ReadAsByteArrayAsync().Result);
38 | //}
39 |
40 | ///
41 | /// Gets the HTTP response body as a
42 | ///
43 | /// An instance of the that the extension should be invoked on.
44 | /// A representation of the HTTP response body.
45 | public static XmlDocument AsXmlDocument(this HttpContent bodyWrapper)
46 | {
47 | var document =
48 | new XmlDocument();
49 | document.LoadXml(bodyWrapper.ReadAsStringAsync().Result);
50 |
51 | return document;
52 | }
53 |
54 | ///
55 | /// Gets the deserialized representation of the JSON in the response body.
56 | ///
57 | /// The type that the JSON response body should be deserialized to.
58 | /// An instance of the that the extension should be invoked on.
59 | /// A instance representation of the HTTP response body.
60 | public static TModel DeserializeJson(this HttpContent bodyWrapper)
61 | {
62 | var serializer =
63 | new JsonSerializer();
64 |
65 | JsonTextReader reader = new JsonTextReader(new StringReader(bodyWrapper.ReadAsStringAsync().Result));
66 |
67 | return serializer.Deserialize(reader);
68 | }
69 |
70 | ///
71 | /// Gets the deserialized representation of the XML in the response body.
72 | ///
73 | /// The type that the XML response body should be deserialized to.
74 | /// An instance of the that the extension should be invoked on.
75 | /// A instance representation of the HTTP response body.
76 | public static TModel DeserializeXml(this HttpContent bodyWrapper)
77 | {
78 | var serializer =
79 | new XmlSerializer(typeof(TModel));
80 |
81 | return (TModel)serializer.Deserialize(bodyWrapper.ReadAsStreamAsync().Result);
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/Fakes/FakeRootPathProvider.cs:
--------------------------------------------------------------------------------
1 | namespace Nancy.Testing.Fakes
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Reflection;
6 |
7 | ///
8 | /// Fake root path provider - set the static property
9 | ///
10 | public class FakeRootPathProvider : IRootPathProvider
11 | {
12 | private static string rootPath;
13 | public static string RootPath
14 | {
15 | get { return rootPath; }
16 | set { rootPath = value; }
17 | }
18 |
19 | static FakeRootPathProvider()
20 | {
21 | var assembly = Assembly.GetEntryAssembly();
22 |
23 | rootPath = assembly == null ? Environment.CurrentDirectory : Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
24 | }
25 |
26 | ///
27 | /// Returns the root folder path of the current Nancy application.
28 | ///
29 | /// A containing the path of the root folder.
30 | string IRootPathProvider.GetRootPath()
31 | {
32 | return RootPath;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/IBrowserContextValues.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | ///
7 | /// Provides an API ontop of for extracting values.
8 | ///
9 | public interface IBrowserContextValues : IHideObjectMembers
10 | {
11 | ///
12 | /// Gets or sets the stream that should be sent with the HTTP request.
13 | ///
14 | /// A that contains the body that should be sent with the HTTP request.
15 | Stream Body { get; set; }
16 |
17 | ///
18 | /// Gets or sets the body string
19 | ///
20 | string BodyString { get; set; }
21 |
22 | ///
23 | /// Gets or sets the form values string
24 | ///
25 | /// If is assigned a value, the will be ignored.
26 | string FormValues { get; set; }
27 |
28 | ///
29 | /// Gets or sets the headers that should be sent with the HTTP request.
30 | ///
31 | /// An instance that contains the headers that should be sent with the HTTP request.
32 | IDictionary> Headers { get; set; }
33 |
34 | ///
35 | /// Gets or sets the protocol that should be sent with the HTTP request.
36 | ///
37 | /// A contains the the protocol that should be sent with the HTTP request.
38 | string Protocol { get; set; }
39 |
40 | ///
41 | /// Gets or sets the querystring
42 | ///
43 | string QueryString { get; set; }
44 |
45 | ///
46 | /// Gets or sets the user host address
47 | ///
48 | string UserHostAddress { get; set; }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/IHideObjectMembers.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel;
6 | using System.Linq;
7 | using System.Text;
8 |
9 | ///
10 | /// Helper interface used to hide the base members from the fluent API to make it much cleaner
11 | /// in Visual Studio intellisense.
12 | ///
13 | /// Created by Daniel Cazzulino http://www.clariusconsulting.net/blogs/kzu/archive/2008/03/10/58301.aspx
14 | [EditorBrowsable(EditorBrowsableState.Never)]
15 | public interface IHideObjectMembers
16 | {
17 | ///
18 | /// Hides the method.
19 | ///
20 | [EditorBrowsable(EditorBrowsableState.Never)]
21 | bool Equals(object obj);
22 |
23 | ///
24 | /// Hides the method.
25 | ///
26 | [EditorBrowsable(EditorBrowsableState.Never)]
27 | int GetHashCode();
28 |
29 | ///
30 | /// Hides the method.
31 | ///
32 | [EditorBrowsable(EditorBrowsableState.Never)]
33 | Type GetType();
34 |
35 | ///
36 | /// Hides the method.
37 | ///
38 | [EditorBrowsable(EditorBrowsableState.Never)]
39 | string ToString();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("WebAPI.Testing")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("WebAPI.Testing")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("57eede70-ef3f-4df9-9408-e08f272cda00")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/ReusableBrowser.cs:
--------------------------------------------------------------------------------
1 | namespace WebAPI.Testing
2 | {
3 | using System.Web.Http;
4 |
5 | public class ReusableBrowser : Browser
6 | {
7 | public ReusableBrowser() : base(false)
8 | {
9 | }
10 |
11 | public ReusableBrowser(HttpConfiguration httpConfiguration) : base(httpConfiguration, false)
12 | {
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/WebAPI.Testing/WebAPI.Testing.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {57EEDE70-EF3F-4DF9-9408-E08F272CDA00}
8 | Library
9 | Properties
10 | WebAPI.Testing
11 | WebAPI.Testing
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
36 | True
37 |
38 |
39 |
40 |
41 | ..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
42 | True
43 |
44 |
45 |
46 | ..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
47 | True
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
80 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/WebAPI.Testing/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------