On Deck + Misc Fixes and Changes (#1215)

* Added playwright and started writing e2e tests.

* To make things easy, disabled other browsers while I get confortable. Added a login flow (assumes my dev env)

* More tests on login page

* Lots more testing code, trying to figure out auth code.

* Ensure we don't track DBs inside config

* Added a new date property for when chapters are added to a series which helps with OnDeck calculations. Changed a lot of heavy api calls to use IEnumerable to stream repsonse to UI.

* Fixed OnDeck with a new field for when last chapter was added on Series. This is a streamlined way to query.

Updated Reading List with NormalizedTitle, CoverImage, CoverImageLocked.

* Implemented the ability to read a random item in the reading list and for the reading list to be intact for order.

* Tweaked the style for webtoon to not span the whole width, but use max width

* When we update a cover image just send an event so we don't need to have logic for when updates occur

* Fixed a bad name for entity type on cover updates

* Aligned the edit collection tag modal to align with new tab design

* Rewrote code for picking the first file for metadata to ensure it always picks the correct file, esp if the first chapter of a series starts with a float (1.1)

* Refactored setting LastChapterAdded to ensure we do it on the Series.

* Updated Chapter updating in scan loop to avoid nested for loop and an additional loop.

* Fixed a bug where locked person fields wouldn't persist between scans.

* Updated Contributing to reflect how to view the swagger api
This commit is contained in:
Joseph Milazzo 2022-04-11 17:43:40 -05:00 committed by GitHub
parent 912dfa8a80
commit 3bbb02f574
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 3397 additions and 343 deletions

View file

@ -9,67 +9,6 @@ namespace API.Tests.Extensions;
public class VolumeListExtensionsTests
{
#region FirstWithChapters
[Fact]
public void FirstWithChapters_ReturnsVolumeWithChapters()
{
var volumes = new List<Volume>()
{
EntityFactory.CreateVolume("0", new List<Chapter>()),
EntityFactory.CreateVolume("1", new List<Chapter>()
{
EntityFactory.CreateChapter("1", false),
EntityFactory.CreateChapter("2", false),
}),
};
Assert.Equal(volumes[1].Number, volumes.FirstWithChapters(false).Number);
Assert.Equal(volumes[1].Number, volumes.FirstWithChapters(true).Number);
}
[Fact]
public void FirstWithChapters_Book()
{
var volumes = new List<Volume>()
{
EntityFactory.CreateVolume("1", new List<Chapter>()
{
EntityFactory.CreateChapter("3", false),
EntityFactory.CreateChapter("4", false),
}),
EntityFactory.CreateVolume("0", new List<Chapter>()
{
EntityFactory.CreateChapter("1", false),
EntityFactory.CreateChapter("0", true),
}),
};
Assert.Equal(volumes[0].Number, volumes.FirstWithChapters(true).Number);
}
[Fact]
public void FirstWithChapters_NonBook()
{
var volumes = new List<Volume>()
{
EntityFactory.CreateVolume("1", new List<Chapter>()
{
EntityFactory.CreateChapter("3", false),
EntityFactory.CreateChapter("4", false),
}),
EntityFactory.CreateVolume("0", new List<Chapter>()
{
EntityFactory.CreateChapter("1", false),
EntityFactory.CreateChapter("0", true),
}),
};
Assert.Equal(volumes[0].Number, volumes.FirstWithChapters(false).Number);
}
#endregion
#region GetCoverImage
[Fact]

View file

@ -17,6 +17,7 @@ namespace API.Tests.Services
{
private readonly ILogger<DirectoryService> _logger = Substitute.For<ILogger<DirectoryService>>();
#region TraverseTreeParallelForEach
[Fact]
public void TraverseTreeParallelForEach_JustArchives_ShouldBe28()
@ -575,19 +576,22 @@ namespace API.Tests.Services
[Fact]
public void CopyFilesToDirectory_ShouldAppendWhenTargetFileExists()
{
const string testDirectory = "/manga/";
var fileSystem = new MockFileSystem();
fileSystem.AddFile($"{testDirectory}file.zip", new MockFileData(""));
fileSystem.AddFile($"/manga/output/file (1).zip", new MockFileData(""));
fileSystem.AddFile($"/manga/output/file (2).zip", new MockFileData(""));
fileSystem.AddFile(MockUnixSupport.Path($"{testDirectory}file.zip"), new MockFileData(""));
fileSystem.AddFile(MockUnixSupport.Path($"/manga/output/file (1).zip"), new MockFileData(""));
fileSystem.AddFile(MockUnixSupport.Path($"/manga/output/file (2).zip"), new MockFileData(""));
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
ds.CopyFilesToDirectory(new []{$"{testDirectory}file.zip"}, "/manga/output/");
ds.CopyFilesToDirectory(new []{$"{testDirectory}file.zip"}, "/manga/output/");
ds.CopyFilesToDirectory(new []{MockUnixSupport.Path($"{testDirectory}file.zip")}, "/manga/output/");
ds.CopyFilesToDirectory(new []{MockUnixSupport.Path($"{testDirectory}file.zip")}, "/manga/output/");
var outputFiles = ds.GetFiles("/manga/output/").Select(API.Parser.Parser.NormalizePath).ToList();
Assert.Equal(4, outputFiles.Count()); // we have 2 already there and 2 copies
// For some reason, this has C:/ on directory even though everything is emulated
Assert.True(outputFiles.Contains(API.Parser.Parser.NormalizePath("/manga/output/file (3).zip")) || outputFiles.Contains(API.Parser.Parser.NormalizePath("C:/manga/output/file (3).zip")));
// For some reason, this has C:/ on directory even though everything is emulated (System.IO.Abstractions issue, not changing)
// https://github.com/TestableIO/System.IO.Abstractions/issues/831
Assert.True(outputFiles.Contains(API.Parser.Parser.NormalizePath("/manga/output/file (3).zip"))
|| outputFiles.Contains(API.Parser.Parser.NormalizePath("C:/manga/output/file (3).zip")));
}
#endregion

View file

@ -22,6 +22,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using Xunit.Sdk;
namespace API.Tests.Services;
@ -703,6 +704,85 @@ public class SeriesServiceTests
Assert.False(series.Metadata.GenresLocked); // GenreLocked is false unless the UI Explicitly says it should be locked
}
[Fact]
public async Task UpdateSeriesMetadata_ShouldAddNewPerson_NoExistingPeople()
{
await ResetDb();
var s = new Series()
{
Name = "Test",
Library = new Library()
{
Name = "Test LIb",
Type = LibraryType.Book,
},
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
};
var g = DbFactory.Person("Existing Person", PersonRole.Publisher);
_context.Series.Add(s);
_context.Person.Add(g);
await _context.SaveChangesAsync();
var success = await _seriesService.UpdateSeriesMetadata(new UpdateSeriesMetadataDto()
{
SeriesMetadata = new SeriesMetadataDto()
{
SeriesId = 1,
Publishers = new List<PersonDto>() {new () {Id = 0, Name = "Existing Person", Role = PersonRole.Publisher}},
},
CollectionTags = new List<CollectionTagDto>()
});
Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.People.Select(g => g.Name).All(g => g == "Existing Person"));
Assert.False(series.Metadata.PublisherLocked); // PublisherLocked is false unless the UI Explicitly says it should be locked
}
[Fact]
public async Task UpdateSeriesMetadata_ShouldAddNewPerson_ExistingPeople()
{
await ResetDb();
var s = new Series()
{
Name = "Test",
Library = new Library()
{
Name = "Test LIb",
Type = LibraryType.Book,
},
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
};
var g = DbFactory.Person("Existing Person", PersonRole.Publisher);
s.Metadata.People = new List<Person>() {DbFactory.Person("Existing Writer", PersonRole.Writer),
DbFactory.Person("Existing Translator", PersonRole.Translator), DbFactory.Person("Existing Publisher 2", PersonRole.Publisher)};
_context.Series.Add(s);
_context.Person.Add(g);
await _context.SaveChangesAsync();
var success = await _seriesService.UpdateSeriesMetadata(new UpdateSeriesMetadataDto()
{
SeriesMetadata = new SeriesMetadataDto()
{
SeriesId = 1,
Publishers = new List<PersonDto>() {new () {Id = 0, Name = "Existing Person", Role = PersonRole.Publisher}},
PublisherLocked = true
},
CollectionTags = new List<CollectionTagDto>()
});
Assert.True(success);
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
Assert.NotNull(series.Metadata);
Assert.True(series.Metadata.People.Select(g => g.Name).All(g => g == "Existing Person"));
Assert.True(series.Metadata.PublisherLocked);
}
[Fact]
public async Task UpdateSeriesMetadata_ShouldLockIfTold()
{
@ -745,4 +825,86 @@ public class SeriesServiceTests
}
#endregion
#region GetFirstChapterForMetadata
private static Series CreateSeriesMock()
{
var files = new List<MangaFile>()
{
EntityFactory.CreateMangaFile("Test.cbz", MangaFormat.Archive, 1)
};
return new Series()
{
Name = "Test",
Library = new Library()
{
Name = "Test LIb",
Type = LibraryType.Manga,
},
Volumes = new List<Volume>()
{
EntityFactory.CreateVolume("0", new List<Chapter>()
{
EntityFactory.CreateChapter("95", false, files, 1),
EntityFactory.CreateChapter("96", false, files, 1),
EntityFactory.CreateChapter("A Special Case", true, files, 1),
}),
EntityFactory.CreateVolume("1", new List<Chapter>()
{
EntityFactory.CreateChapter("1", false, files, 1),
EntityFactory.CreateChapter("2", false, files, 1),
}),
EntityFactory.CreateVolume("2", new List<Chapter>()
{
EntityFactory.CreateChapter("21", false, files, 1),
EntityFactory.CreateChapter("22", false, files, 1),
}),
EntityFactory.CreateVolume("3", new List<Chapter>()
{
EntityFactory.CreateChapter("31", false, files, 1),
EntityFactory.CreateChapter("32", false, files, 1),
}),
}
};
}
[Fact]
public void GetFirstChapterForMetadata_Book_Test()
{
var series = CreateSeriesMock();
var firstChapter = SeriesService.GetFirstChapterForMetadata(series, true);
Assert.Same("1", firstChapter.Range);
}
[Fact]
public void GetFirstChapterForMetadata_NonBook_ShouldReturnVolume1()
{
var series = CreateSeriesMock();
var firstChapter = SeriesService.GetFirstChapterForMetadata(series, false);
Assert.Same("1", firstChapter.Range);
}
[Fact]
public void GetFirstChapterForMetadata_NonBook_ShouldReturnVolume1_WhenFirstChapterIsFloat()
{
var series = CreateSeriesMock();
var files = new List<MangaFile>()
{
EntityFactory.CreateMangaFile("Test.cbz", MangaFormat.Archive, 1)
};
series.Volumes[1].Chapters = new List<Chapter>()
{
EntityFactory.CreateChapter("2", false, files, 1),
EntityFactory.CreateChapter("1.1", false, files, 1),
EntityFactory.CreateChapter("1.2", false, files, 1),
};
var firstChapter = SeriesService.GetFirstChapterForMetadata(series, false);
Assert.Same("1.1", firstChapter.Range);
}
#endregion
}