Skip to content

Feature/skill table #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jul 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace LinkDotNet.Blog.IntegrationTests.Infrastructure.Persistence.Sql
{
public sealed class BlogPostRepositoryTests : SqlDatabaseTestBase
public sealed class BlogPostRepositoryTests : SqlDatabaseTestBase<BlogPost>
{
[Fact]
public async Task ShouldLoadBlogPost()
Expand All @@ -17,7 +17,7 @@ public async Task ShouldLoadBlogPost()
await DbContext.BlogPosts.AddAsync(blogPost);
await DbContext.SaveChangesAsync();

var blogPostFromRepo = await BlogPostRepository.GetByIdAsync(blogPost.Id);
var blogPostFromRepo = await Repository.GetByIdAsync(blogPost.Id, post => post.Tags);

blogPostFromRepo.Should().NotBeNull();
blogPostFromRepo.Title.Should().Be("Title");
Expand All @@ -35,7 +35,7 @@ public async Task ShouldSaveBlogPost()
{
var blogPost = BlogPost.Create("Title", "Subtitle", "Content", "url", true, tags: new[] { "Tag 1", "Tag 2" });

await BlogPostRepository.StoreAsync(blogPost);
await Repository.StoreAsync(blogPost);

var blogPostFromContext = await DbContext.BlogPosts.Include(b => b.Tags).AsNoTracking().SingleOrDefaultAsync(s => s.Id == blogPost.Id);
blogPostFromContext.Should().NotBeNull();
Expand All @@ -56,7 +56,7 @@ public async Task ShouldGetAllBlogPosts()
await DbContext.BlogPosts.AddAsync(blogPost);
await DbContext.SaveChangesAsync();

var blogPostsFromRepo = (await BlogPostRepository.GetAllAsync()).ToList();
var blogPostsFromRepo = (await Repository.GetAllAsync(include: post => post.Tags)).ToList();

blogPostsFromRepo.Should().NotBeNull();
blogPostsFromRepo.Should().HaveCount(1);
Expand All @@ -77,11 +77,11 @@ public async Task ShouldBeUpdateable()
var blogPost = new BlogPostBuilder().Build();
await DbContext.BlogPosts.AddAsync(blogPost);
await DbContext.SaveChangesAsync();
var blogPostFromDb = await BlogPostRepository.GetByIdAsync(blogPost.Id);
var blogPostFromDb = await Repository.GetByIdAsync(blogPost.Id);
var updater = new BlogPostBuilder().WithTitle("New Title").Build();
blogPostFromDb.Update(updater);

await BlogPostRepository.StoreAsync(blogPostFromDb);
await Repository.StoreAsync(blogPostFromDb);

var blogPostAfterSave = await DbContext.BlogPosts.AsNoTracking().SingleAsync(b => b.Id == blogPostFromDb.Id);
blogPostAfterSave.Title.Should().Be("New Title");
Expand All @@ -93,13 +93,14 @@ public async Task ShouldFilterAndOrder()
var olderPost = new BlogPostBuilder().Build();
var newerPost = new BlogPostBuilder().Build();
var filteredOutPost = new BlogPostBuilder().WithTitle("FilterOut").Build();
await BlogPostRepository.StoreAsync(olderPost);
await BlogPostRepository.StoreAsync(newerPost);
await BlogPostRepository.StoreAsync(filteredOutPost);
await Repository.StoreAsync(olderPost);
await Repository.StoreAsync(newerPost);
await Repository.StoreAsync(filteredOutPost);

var blogPosts = await BlogPostRepository.GetAllAsync(
var blogPosts = await Repository.GetAllAsync(
bp => bp.Title != "FilterOut",
bp => bp.UpdatedDate,
null,
false);

var retrievedPosts = blogPosts.ToList();
Expand All @@ -112,9 +113,9 @@ public async Task ShouldFilterAndOrder()
public async Task ShouldDelete()
{
var blogPost = new BlogPostBuilder().Build();
await BlogPostRepository.StoreAsync(blogPost);
await Repository.StoreAsync(blogPost);

await BlogPostRepository.DeleteAsync(blogPost.Id);
await Repository.DeleteAsync(blogPost.Id);

(await DbContext.BlogPosts.AsNoTracking().AnyAsync(b => b.Id == blogPost.Id)).Should().BeFalse();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
using System.Threading.Tasks;
using FluentAssertions;
using LinkDotNet.Blog.TestUtilities;
using LinkDotNet.Domain;
using Xunit;

namespace LinkDotNet.Blog.IntegrationTests.Infrastructure.Persistence.Sql
{
public class ProfileRepositoryTests : SqlDatabaseTestBase
public class ProfileRepositoryTests : SqlDatabaseTestBase<ProfileInformationEntry>
{
[Fact]
public async Task ShouldSaveAndRetrieveAllEntries()
{
var item1 = new ProfileInformationEntryBuilder().WithContent("key1").Build();
var item2 = new ProfileInformationEntryBuilder().WithContent("key2").Build();
await ProfileRepository.StoreAsync(item1);
await ProfileRepository.StoreAsync(item2);
await Repository.StoreAsync(item1);
await Repository.StoreAsync(item2);

var items = await ProfileRepository.GetAllAsync();
var items = await Repository.GetAllAsync();

items[0].Content.Should().Be("key1");
items[1].Content.Should().Be("key2");
Expand All @@ -26,12 +27,12 @@ public async Task ShouldDelete()
{
var item1 = new ProfileInformationEntryBuilder().WithContent("key1").Build();
var item2 = new ProfileInformationEntryBuilder().WithContent("key2").Build();
await ProfileRepository.StoreAsync(item1);
await ProfileRepository.StoreAsync(item2);
await Repository.StoreAsync(item1);
await Repository.StoreAsync(item2);

await ProfileRepository.DeleteAsync(item1.Id);
await Repository.DeleteAsync(item1.Id);

var items = await ProfileRepository.GetAllAsync();
var items = await Repository.GetAllAsync();
items.Should().HaveCount(1);
items[0].Id.Should().Be(item2.Id);
}
Expand All @@ -40,11 +41,11 @@ public async Task ShouldDelete()
public async Task NoopOnDeleteWhenEntryNotFound()
{
var item = new ProfileInformationEntryBuilder().WithContent("key1").Build();
await ProfileRepository.StoreAsync(item);
await Repository.StoreAsync(item);

await ProfileRepository.DeleteAsync("SomeIdWhichHopefullyDoesNotExist");
await Repository.DeleteAsync("SomeIdWhichHopefullyDoesNotExist");

(await ProfileRepository.GetAllAsync()).Should().HaveCount(1);
(await Repository.GetAllAsync()).Should().HaveCount(1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Threading.Tasks;
using FluentAssertions;
using LinkDotNet.Blog.TestUtilities;
using LinkDotNet.Domain;
using Xunit;

namespace LinkDotNet.Blog.IntegrationTests.Infrastructure.Persistence.Sql
{
public class SkillRepositoryTests : SqlDatabaseTestBase<Skill>
{
[Fact]
public async Task ShouldSaveAndRetrieveAllEntries()
{
var skill = new SkillBuilder()
.WithSkillName("C#")
.WithIconUrl("url")
.WithCapability("Backend")
.WithProficiencyLevel(ProficiencyLevel.Expert).Build();
await Repository.StoreAsync(skill);

var items = await Repository.GetAllAsync();

items.Should().HaveCount(1);
items[0].Name.Should().Be("C#");
items[0].IconUrl.Should().Be("url");
items[0].Capability.Should().Be("Backend");
items[0].ProficiencyLevel.Should().Be(ProficiencyLevel.Expert);
}

[Fact]
public async Task ShouldDelete()
{
var skill1 = new SkillBuilder().Build();
var skill2 = new SkillBuilder().Build();
await Repository.StoreAsync(skill1);
await Repository.StoreAsync(skill2);

await Repository.DeleteAsync(skill1.Id);

var items = await Repository.GetAllAsync();
items.Should().HaveCount(1);
items[0].Id.Should().Be(skill2.Id);
}

[Fact]
public async Task NoopOnDeleteWhenEntryNotFound()
{
var item = new SkillBuilder().Build();
await Repository.StoreAsync(item);

await Repository.DeleteAsync("SomeIdWhichHopefullyDoesNotExist");

(await Repository.GetAllAsync()).Should().HaveCount(1);
}
}
}
11 changes: 5 additions & 6 deletions LinkDotNet.Blog.IntegrationTests/SqlDatabaseTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
using System;
using System.Data.Common;
using System.Threading.Tasks;
using LinkDotNet.Domain;
using LinkDotNet.Infrastructure.Persistence.Sql;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Xunit;

namespace LinkDotNet.Blog.IntegrationTests
{
public abstract class SqlDatabaseTestBase : IAsyncLifetime, IAsyncDisposable
public abstract class SqlDatabaseTestBase<TEntity> : IAsyncLifetime, IAsyncDisposable
where TEntity : Entity
{
protected SqlDatabaseTestBase()
{
var options = new DbContextOptionsBuilder()
.UseSqlite(CreateInMemoryConnection())
.Options;
DbContext = new BlogDbContext(options);
BlogPostRepository = new BlogPostRepository(new BlogDbContext(options));
ProfileRepository = new ProfileRepository(new BlogDbContext(options));
Repository = new Repository<TEntity>(new BlogDbContext(options));
}

protected BlogPostRepository BlogPostRepository { get; }

protected ProfileRepository ProfileRepository { get; }
protected Repository<TEntity> Repository { get; }

protected BlogDbContext DbContext { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,25 @@
using LinkDotNet.Blog.TestUtilities;
using LinkDotNet.Blog.Web.Pages.Admin;
using LinkDotNet.Blog.Web.Shared;
using LinkDotNet.Domain;
using LinkDotNet.Infrastructure.Persistence;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace LinkDotNet.Blog.IntegrationTests.Web.Pages.Admin
{
public class DraftBlogPostPageTests : SqlDatabaseTestBase
public class DraftBlogPostPageTests : SqlDatabaseTestBase<BlogPost>
{
[Fact]
public async Task ShouldOnlyShowPublishedPosts()
{
var publishedPost = new BlogPostBuilder().WithTitle("Published").IsPublished().Build();
var unpublishedPost = new BlogPostBuilder().WithTitle("Not published").IsPublished(false).Build();
await BlogPostRepository.StoreAsync(publishedPost);
await BlogPostRepository.StoreAsync(unpublishedPost);
await Repository.StoreAsync(publishedPost);
await Repository.StoreAsync(unpublishedPost);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.Services.AddScoped<IBlogPostRepository>(_ => BlogPostRepository);
ctx.Services.AddScoped<IRepository<BlogPost>>(_ => Repository);
var cut = ctx.RenderComponent<DraftBlogPosts>();
cut.WaitForState(() => cut.FindAll(".blog-card").Any());

Expand Down
11 changes: 6 additions & 5 deletions LinkDotNet.Blog.IntegrationTests/Web/Pages/BlogPostPageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using LinkDotNet.Blog.TestUtilities;
using LinkDotNet.Blog.Web.Pages;
using LinkDotNet.Blog.Web.Shared;
using LinkDotNet.Domain;
using LinkDotNet.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -16,13 +17,13 @@

namespace LinkDotNet.Blog.IntegrationTests.Web.Pages
{
public class BlogPostPageTests : SqlDatabaseTestBase
public class BlogPostPageTests : SqlDatabaseTestBase<BlogPost>
{
[Fact]
public async Task ShouldAddLikeOnEvent()
{
var publishedPost = new BlogPostBuilder().WithLikes(2).IsPublished().Build();
await BlogPostRepository.StoreAsync(publishedPost);
await Repository.StoreAsync(publishedPost);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
RegisterComponents(ctx);
Expand All @@ -42,7 +43,7 @@ public async Task ShouldAddLikeOnEvent()
public async Task ShouldSubtractLikeOnEvent()
{
var publishedPost = new BlogPostBuilder().WithLikes(2).IsPublished().Build();
await BlogPostRepository.StoreAsync(publishedPost);
await Repository.StoreAsync(publishedPost);
using var ctx = new TestContext();
var localStorage = new Mock<ILocalStorageService>();
localStorage.Setup(l => l.ContainKeyAsync("hasLiked", default)).ReturnsAsync(true);
Expand All @@ -65,7 +66,7 @@ public async Task ShouldSubtractLikeOnEvent()
public async Task ShouldSetTagsWhenAvailable()
{
var publishedPost = new BlogPostBuilder().IsPublished().WithTags("Tag1,Tag2").Build();
await BlogPostRepository.StoreAsync(publishedPost);
await Repository.StoreAsync(publishedPost);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
ctx.AddTestAuthorization();
Expand All @@ -80,7 +81,7 @@ public async Task ShouldSetTagsWhenAvailable()

private void RegisterComponents(TestContextBase ctx, ILocalStorageService localStorageService = null)
{
ctx.Services.AddScoped<IBlogPostRepository>(_ => BlogPostRepository);
ctx.Services.AddScoped<IRepository<BlogPost>>(_ => Repository);
ctx.Services.AddScoped(_ => localStorageService ?? new Mock<ILocalStorageService>().Object);
ctx.Services.AddScoped(_ => new Mock<IToastService>().Object);
ctx.Services.AddScoped(_ => new Mock<IHeadElementHelper>().Object);
Expand Down
14 changes: 7 additions & 7 deletions LinkDotNet.Blog.IntegrationTests/Web/Pages/IndexTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@

namespace LinkDotNet.Blog.IntegrationTests.Web.Pages
{
public class IndexTests : SqlDatabaseTestBase
public class IndexTests : SqlDatabaseTestBase<BlogPost>
{
[Fact]
public async Task ShouldShowAllBlogPostsWithLatestOneFirst()
{
var oldestBlogPost = new BlogPostBuilder().WithTitle("Old").Build();
var newestBlogPost = new BlogPostBuilder().WithTitle("New").Build();
await BlogPostRepository.StoreAsync(oldestBlogPost);
await BlogPostRepository.StoreAsync(newestBlogPost);
await Repository.StoreAsync(oldestBlogPost);
await Repository.StoreAsync(newestBlogPost);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
RegisterComponents(ctx);
Expand All @@ -42,8 +42,8 @@ public async Task ShouldOnlyShowPublishedPosts()
{
var publishedPost = new BlogPostBuilder().WithTitle("Published").IsPublished().Build();
var unpublishedPost = new BlogPostBuilder().WithTitle("Not published").IsPublished(false).Build();
await BlogPostRepository.StoreAsync(publishedPost);
await BlogPostRepository.StoreAsync(unpublishedPost);
await Repository.StoreAsync(publishedPost);
await Repository.StoreAsync(unpublishedPost);
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
RegisterComponents(ctx);
Expand Down Expand Up @@ -126,13 +126,13 @@ private async Task CreatePublishedBlogPosts(int amount)
for (var i = 0; i < amount; i++)
{
var blogPost = new BlogPostBuilder().IsPublished().Build();
await BlogPostRepository.StoreAsync(blogPost);
await Repository.StoreAsync(blogPost);
}
}

private void RegisterComponents(TestContextBase ctx)
{
ctx.Services.AddScoped<IBlogPostRepository>(_ => BlogPostRepository);
ctx.Services.AddScoped<IRepository<BlogPost>>(_ => Repository);
ctx.Services.AddScoped(_ => CreateSampleAppConfiguration());
ctx.Services.AddScoped(_ => new Mock<IHeadElementHelper>().Object);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using FluentAssertions;
using LinkDotNet.Blog.TestUtilities;
using LinkDotNet.Blog.Web.Pages;
using LinkDotNet.Domain;
using LinkDotNet.Infrastructure.Persistence;
using Microsoft.Extensions.DependencyInjection;
using Moq;
Expand All @@ -13,7 +14,7 @@

namespace LinkDotNet.Blog.IntegrationTests.Web.Pages
{
public class SearchByTagTests : SqlDatabaseTestBase
public class SearchByTagTests : SqlDatabaseTestBase<BlogPost>
{
[Fact]
public async Task ShouldOnlyDisplayTagsGivenByParameter()
Expand All @@ -22,7 +23,7 @@ public async Task ShouldOnlyDisplayTagsGivenByParameter()
await AddBlogPostWithTagAsync("Tag 1");
await AddBlogPostWithTagAsync("Tag 1");
await AddBlogPostWithTagAsync("Tag 2");
ctx.Services.AddScoped<IBlogPostRepository>(_ => BlogPostRepository);
ctx.Services.AddScoped<IRepository<BlogPost>>(_ => Repository);
ctx.Services.AddScoped(_ => new Mock<IHeadElementHelper>().Object);
var cut = ctx.RenderComponent<SearchByTag>(p => p.Add(s => s.Tag, "Tag 1"));
cut.WaitForState(() => cut.FindAll(".blog-card").Any());
Expand All @@ -37,7 +38,7 @@ public async Task ShouldHandleSpecialCharacters()
{
using var ctx = new TestContext();
await AddBlogPostWithTagAsync("C#");
ctx.Services.AddScoped<IBlogPostRepository>(_ => BlogPostRepository);
ctx.Services.AddScoped<IRepository<BlogPost>>(_ => Repository);
ctx.Services.AddScoped(_ => new Mock<IHeadElementHelper>().Object);
var cut = ctx.RenderComponent<SearchByTag>(p => p.Add(s => s.Tag, Uri.EscapeDataString("C#")));
cut.WaitForState(() => cut.FindAll(".blog-card").Any());
Expand Down
Loading