Adding a _ViewStart page to define the Layoutpage

Removing the Layout page reference from individual cshtml files.
Added some tests to verify layout getting rendered in every view.
Added a couple of verifications to verify that title of the page is set appropriately.
This commit is contained in:
Praburaj 2014-07-30 14:56:20 -07:00
parent 75d9ef5e0d
commit 644c45ae5c
20 changed files with 95 additions and 107 deletions

View File

@ -61,6 +61,7 @@
<Content Include="Views\Home\Index.cshtml" />
<Content Include="Views\Shared\Components\CartSummary\Default.cshtml" />
<Content Include="Views\Shared\Components\GenreMenu\Default.cshtml" />
<Content Include="Views\Shared\Components\_ViewStart.cshtml" />
<Content Include="Views\Shared\Error.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />
<Content Include="Views\Shared\_LoginPartial.cshtml" />
@ -73,6 +74,7 @@
<Content Include="Views\Store\Browse.cshtml" />
<Content Include="Views\Store\Details.cshtml" />
<Content Include="Views\Store\Index.cshtml" />
<Content Include="Views\_ViewStart.cshtml" />
<Content Include="web.config" />
<Content Include="web.Debug.config" />
<Content Include="web.Release.config" />

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.LoginViewModel
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Log in";
}

View File

@ -1,6 +1,4 @@
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Manage Account";
}

View File

@ -1,7 +1,5 @@
@model MusicStore.Models.RegisterViewModel
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Register";
}

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Order
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Address And Payment";
}

View File

@ -1,8 +1,6 @@
@model int
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Checkout Complete";
}

View File

@ -1,6 +1,4 @@
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Home Page";
}

View File

@ -0,0 +1,4 @@
@{
//_ViewStart is applicable to ViewComponents as well. Since the layout page renders the ViewComponents in this case adding an override to Layout page to prevent StackOverFlowException.
Layout = null;
}

View File

@ -1,6 +1,4 @@
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Error";
}

View File

@ -1,7 +1,5 @@
@model MusicStore.ViewModels.ShoppingCartViewModel
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Shopping Cart";
}

View File

@ -1,7 +1,5 @@
@model MusicStore.Models.Genre
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Browse Albums";
}
<div class="genre">

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Album
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Album - " + Model.Title;
}

View File

@ -1,17 +1,15 @@
@model IEnumerable<MusicStore.Models.Genre>
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
@{
ViewBag.Title = "Store";
}
<h3>Browse Genres</h3>
<p>
Select from @Model.Count() genres:
</p>
<ul class="list-group">
@foreach (var genre in Model)
{
<li class="list-group-item">@Html.ActionLink(genre.Name, "Browse", new { genre = genre.Name })</li>
}
</ul>
<p>
Select from @Model.Count() genres:
</p>
<ul class="list-group">
@foreach (var genre in Model)
{
<li class="list-group-item">@Html.ActionLink(genre.Name, "Browse", new { genre = genre.Name })</li>
}
</ul>

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Album
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Create";
}

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Album
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Details";
}

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Album
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Edit";
}

View File

@ -1,66 +1,64 @@
@model IEnumerable<MusicStore.Models.Album>
@helper Truncate(string input, int length)
@helper Truncate(string input, int length)
{
if (input.Length <= length)
{
@input
}
else
{
@input.Substring(0, length)<text>...</text>
}
if (input.Length <= length)
{
@input
}
else
{
@input.Substring(0, length)<text>...</text>
}
}
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Index";
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Genre.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Artist.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Title)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Price)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.ValueFor(modelItem => item.Genre.Name)
</td>
<td>
@Truncate(item.Artist.Name, 25)
</td>
<td>
@Truncate(item.Title, 25)
</td>
<td>
@Html.ValueFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id = item.AlbumId }) |
@Html.ActionLink("Delete", "RemoveAlbum", new { id = item.AlbumId })
</td>
</tr>
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Genre.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Artist.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Title)
</th>
<th>
@Html.DisplayNameFor(model => model.FirstOrDefault().Price)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.ValueFor(modelItem => item.Genre.Name)
</td>
<td>
@Truncate(item.Artist.Name, 25)
</td>
<td>
@Truncate(item.Title, 25)
</td>
<td>
@Html.ValueFor(modelItem => item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.AlbumId }) |
@Html.ActionLink("Details", "Details", new { id = item.AlbumId }) |
@Html.ActionLink("Delete", "RemoveAlbum", new { id = item.AlbumId })
</td>
</tr>
}
</table>
</table>

View File

@ -1,8 +1,6 @@
@model MusicStore.Models.Album
@{
//TODO: Until we have a way to specify the layout page at application level.
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Delete";
}

View File

@ -0,0 +1,3 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
}

View File

@ -178,12 +178,9 @@ namespace E2ETests
{
Console.WriteLine("Home page content : {0}", responseContent);
Assert.Equal<HttpStatusCode>(HttpStatusCode.OK, response.StatusCode);
Assert.Contains("ASP.NET MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<li><a href=\"/\">Home</a></li>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<a href=\"/Store\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">Store <b class=\"caret\"></b></a>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<ul class=\"dropdown-menu\">", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<li class=\"divider\"></li>", responseContent, StringComparison.OrdinalIgnoreCase);
ValidateLayoutPage(responseContent);
Assert.Contains("<a href=\"/Store/Details/", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<title>Home Page MVC Music Store</title>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Register", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("Login", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("mvcmusicstore.codeplex.com", responseContent, StringComparison.OrdinalIgnoreCase);
@ -191,12 +188,23 @@ namespace E2ETests
Console.WriteLine("Application initialization successful.");
}
private void ValidateLayoutPage(string responseContent)
{
Assert.Contains("ASP.NET MVC Music Store", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<li><a href=\"/\">Home</a></li>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<a href=\"/Store\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">Store <b class=\"caret\"></b></a>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<ul class=\"dropdown-menu\">", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<li class=\"divider\"></li>", responseContent, StringComparison.OrdinalIgnoreCase);
}
private void AccessStoreWithoutPermissions(string userName = null)
{
Console.WriteLine("Trying to access StoreManager that needs ManageStore claim with the current user : {0}", userName ?? "Anonymous");
var response = httpClient.GetAsync("/StoreManager/").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
ValidateLayoutPage(responseContent);
Assert.Contains("<title>Log in MVC Music Store</title>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Contains("<h4>Use a local account to log in.</h4>", responseContent, StringComparison.OrdinalIgnoreCase);
Assert.Equal<string>(ApplicationBaseUrl + "Account/Login?ReturnUrl=%2FStoreManager%2F", response.RequestMessage.RequestUri.AbsoluteUri);
Console.WriteLine("Redirected to login page as expected.");
@ -218,6 +226,7 @@ namespace E2ETests
var response = httpClient.GetAsync("/Account/Register").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
ValidateLayoutPage(responseContent);
var generatedUserName = Guid.NewGuid().ToString().Replace("-", string.Empty);
Console.WriteLine("Creating a new user with name '{0}'", generatedUserName);
@ -242,6 +251,7 @@ namespace E2ETests
var response = httpClient.GetAsync("/Account/Register").Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
ValidateLayoutPage(responseContent);
var generatedUserName = Guid.NewGuid().ToString().Replace("-", string.Empty);
Console.WriteLine("Creating a new user with name '{0}'", generatedUserName);
@ -292,6 +302,7 @@ namespace E2ETests
var response = httpClient.GetAsync(string.Empty).Result;
ThrowIfResponseStatusNotOk(response);
var responseContent = response.Content.ReadAsStringAsync().Result;
ValidateLayoutPage(responseContent);
var formParameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/LogOff")),