From f125b17eaf1ca068a283c15576e91b2e313ff250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 15 Aug 2019 10:52:59 +0300 Subject: [PATCH 1/9] Revised Angular tutorial Part II --- docs/en/Tutorials/Angular/Part-I.md | 1 + docs/en/Tutorials/Angular/Part-II.md | 176 ++++++++--------- docs/en/Tutorials/Angular/Part-III.md | 178 ++++++++++++++++++ .../images/bookstore-test-projects-v2.png | Bin 0 -> 6864 bytes 4 files changed, 262 insertions(+), 93 deletions(-) create mode 100644 docs/en/Tutorials/Angular/Part-III.md create mode 100644 docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png diff --git a/docs/en/Tutorials/Angular/Part-I.md b/docs/en/Tutorials/Angular/Part-I.md index fdfddef683..6dadc24841 100644 --- a/docs/en/Tutorials/Angular/Part-I.md +++ b/docs/en/Tutorials/Angular/Part-I.md @@ -8,6 +8,7 @@ This is the first part of the Angular tutorial series. See all parts: - **Part I: Create the project and a book list page (this tutorial)** - [Part II: Create, Update and Delete books](Part-II.md) +- [Part III: Integration Tests](Part-III.md) You can access to the **source code** of the application from the [GitHub repository](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb). diff --git a/docs/en/Tutorials/Angular/Part-II.md b/docs/en/Tutorials/Angular/Part-II.md index b322783db3..f18ec9dce1 100644 --- a/docs/en/Tutorials/Angular/Part-II.md +++ b/docs/en/Tutorials/Angular/Part-II.md @@ -6,6 +6,7 @@ This is the second part of the Angular tutorial series. See all parts: - [Part I: Create the project and a book list page](Part-I.md) - **Part II: Create, Update and Delete books (this tutorial)** +- [Part III: Integration Tests](Part-III.md) You can access to the **source code** of the application from the [GitHub repository](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb). @@ -37,19 +38,19 @@ Open the `books.service.ts` and add a new method, named `create` to perform an H ```typescript create(body: Books.CreateUpdateBookInput): Observable { - const request: Rest.Request = { + return this.rest.request({ method: 'POST', url: '/api/app/book', body, - }; - - return this.rest.request(request); + }); } ``` +* `rest.request` function gets generic parameters for the types sent to and received from the server. This example sends a `CreateUpdateBookInput` object and receives a `Book` object (you can set `void` for request or return type if not used). + #### State Definitions -Add the `CreateUpdateBook` action to `books.actions.ts` as shown below: +Add the `CreateUpdateBook` action to the `books.actions.ts` as shown below: ```typescript import { Books } from '../models'; @@ -78,7 +79,7 @@ When the `SaveBook` action dispatched, the save method is executed. It call `cre #### Add a Modal to BookListComponent -Open the `book-list.component.html` and add the `abp-modal` to show/hide the book form. +Open the `book-list.component.html` and add the `abp-modal` to show/hide the modal to create a new book. ```html @@ -98,7 +99,7 @@ Open the `book-list.component.html` and add the `abp-modal` to show/hide the boo `abp-modal` is a pre-built component to show modals. While you could use another approach to show a modal, `abp-modal` provides additional benefits. -Add a button, labeled `New book` to show the modal. +Add a button, labeled `New book` to show the modal: ```html
@@ -161,8 +162,8 @@ buildForm() { } ``` -- The `group` method of `FormBuilder` creates a `FormGroup`. -- Added `Validators.required` static method that validation of form element. +- The `group` method of `FormBuilder` (`fb`) creates a `FormGroup`. +- Added `Validators.required` static method that validates the related form element. Modify the `onAdd` method as shown below: @@ -173,7 +174,7 @@ onAdd() { } ``` -### Create the DOM Elements of the Form +#### Create the DOM Elements of the Form Open `book-list.component.html` and add the form in the body template of the modal. @@ -213,28 +214,32 @@ Open `book-list.component.html` and add the form in the body template of the mod ``` -TODO: Add a short description. +* This template creates a form with Name, Price, Type and Publish date fields. > We've used [NgBootstrap datepicker](https://ng-bootstrap.github.io/#/components/datepicker/overview) in this component. -Open the `book-list.component.ts` and then add the `bookTypes`. +Open the `book-list.component.ts` and then create an array, named `bookTypeArr`: ```typescript //... form: FormGroup; -bookTypeArr = Object.keys(Books.BookType).filter(bookType => typeof this.booksType[bookType] === 'number'); +bookTypeArr = Object.keys(Books.BookType).filter( + bookType => typeof this.booksType[bookType] === 'number' +); ``` -The `bookTypes` variable added to generate array from `BookType` enum. The `bookTypes` equals like this: +The `bookTypeArr` contains the fields of the `BookType` enum. Resulting array is shown below: ```js ['Adventure', 'Biography', 'Dystopia', 'Fantastic' ...] ``` -### Add the Datepicker Requirements +This array was used in the previous form template (in the `ngFor` loop). -Import `NgbDatepickerModule` to the `books.module.ts`. +#### Datepicker Requirements + +You need to import `NgbDatepickerModule` to the `books.module.ts`: ```typescript import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; @@ -248,25 +253,39 @@ import { NgbDatepickerModule } from '@ng-bootstrap/ng-bootstrap'; export class BooksModule {} ``` -Open the `book-list.component.html` and then add `providers` as shown below: +Then open the `book-list.component.html` and add `providers` as shown below: ```typescript @Component({ // ... - styleUrls: ['./book-list.component.scss'], providers: [{ provide: NgbDateAdapter, useClass: NgbDateNativeAdapter }], }) export class BookListComponent implements OnInit { // ... ``` -> The `NgbDateAdapter` convert Datepicker value type to `Date` type. See the [datepicker adapters](https://ng-bootstrap.github.io/#/components/datepicker/overview) for more details. +> The `NgbDateAdapter` converts Datepicker value to `Date` type. See the [datepicker adapters](https://ng-bootstrap.github.io/#/components/datepicker/overview) for more details. ![new-book-form](images/bookstore-new-book-form.png) -### Create a New Book +#### Saving the Book -Add the `save` method to `BookListComponent` +Open the `book-list.component.html` and add an `abp-button` to save the form. + +```html + + + Save + +``` + +This adds a save button to the bottom area of the modal: + +![bookstore-new-book-form-v2](images/bookstore-new-book-form-v2.png) + +Then define a `save` method in the `BookListComponent`: ```typescript save() { @@ -281,56 +300,32 @@ save() { } ``` -TODO: description ?? +### Updating An Existing Book -Then, open the `book-list.component.html` and add the `abp-button` for the run `save` method. - -```html - - - Save - -``` - -Now, You can add a new book. - -![bookstore-new-book-form-v2](images/bookstore-new-book-form-v2.png) - -### Add HTTP GET and PUT Methods - -TODO: Description +#### BooksService Open the `books.service.ts` and then add the `getById` and `update` methods. ```typescript getById(id: string): Observable { - const request: Rest.Request = { + return this.rest.request({ method: 'GET', url: `/api/app/book/${id}`, - }; - - return this.rest.request(request); + }); } update(body: Books.CreateUpdateBookInput, id: string): Observable { - const request: Rest.Request = { + return this.rest.request({ method: 'PUT', url: `/api/app/book/${id}`, body, - }; - - return this.rest.request(request); + }); } ``` -- Added the `getById` method to get the editing book by performing an HTTP request to the related endpoint. -- Added the `update` method to update a book with the `id` by performing an HTTP request to the related endpoint. - -TODO: header ?? +#### CreateUpdateBook Action -Open the `books.actins.ts` and add `id` parameter. +Open the `books.actins.ts` and add `id` parameter to the `CreateUpdateBook` action: ```typescript export class CreateUpdateBook { @@ -339,9 +334,7 @@ export class CreateUpdateBook { } ``` -Added `id` parameter to reuse the `BooksSave` while updating and creating a book. - -Open `books.state.ts` and then modify the `save` method as show below: +Open `books.state.ts` and modify the `save` method as show below: ```typescript @Action(CreateUpdateBook) @@ -358,9 +351,9 @@ save({ dispatch }: StateContext, { payload, id }: CreateUpdateBook) } ``` -### Update a Book +#### BookListComponent -Inject `BooksService` dependency by adding it to the `book-list.component.ts` constructor and add variable named `selectedBook`. +Inject `BooksService` dependency by adding it to the `book-list.component.ts` constructor and add a variable named `selectedBook`. ```typescript import { BooksService } from '../shared/books.service'; @@ -373,10 +366,7 @@ constructor( ) ``` -- Added `booksService` to get the detail of selected book by `id` before creating the form -- Added `selectedBook` variable to reuse detail of selected book. - -Modify the `buildForm` method to reuse the same form while editing a book. +`booksService` is used to get the editing book to prepare the form. Modify the `buildForm` method to reuse the same form while editing a book. ```typescript buildForm() { @@ -401,9 +391,9 @@ Add the `onEdit` method as shown below: } ``` -- Added `onEdit` method to get selected book detail, build form and then show the modal. +Added `onEdit` method to get the editing book, build the form and show the modal. -Add the `selectedBook` definition to `onAdd` method for reuse same form while adding a new book. +Now, add the `selectedBook` definition to `onAdd` method to reuse the same form while creating a new book: ```typescript onAdd() { @@ -412,7 +402,7 @@ Add the `selectedBook` definition to `onAdd` method for reuse same form while ad } ``` -Modify the `save` method as shown below: +Modify the `save` method to pass the id of the selected book as shown below: ```typescript save() { @@ -428,8 +418,6 @@ save() { } ``` -Added the `this.selectedBook.id` property to reuse the `CreateUpdateBook` action. - #### Add "Actions" Dropdown to the Table Open the `book-list.component.html` and add modify the `p-table` as shown below: @@ -471,15 +459,16 @@ Open the `book-list.component.html` and add modify the `p-table` as shown belo ``` -Actions button added to each row of the table. +* Added a `th` for the "Actions" column. +* Added `button` with `ngbDropdownToggle` to open actions when clicked the button. > We've used to [NgbDropdown](https://ng-bootstrap.github.io/#/components/dropdown/examples) for the dropdown menu of actions. -The Actions buttons looks like this: +The final UI looks like: ![actions-buttons](images/bookstore-actions-buttons.png) -Update the modal header for reuse the same modal. +Update the modal header to change the title based on the current operation: ```html @@ -489,26 +478,24 @@ Update the modal header for reuse the same modal. ![actions-buttons](images/bookstore-edit-modal.png) -TODO: description & screenshot ?? +### Deleting an Existing Book -### Delete a Book +#### BooksService -Open `books.service.ts` and the the `delete` method for delete a book with the `id` by performing an HTTP request to the related endpoint. +Open `books.service.ts` and add a `delete` method to delete a book with the `id` by performing an HTTP request to the related endpoint: ```typescript -delete(id: string): Observable { - const request: Rest.Request = { +delete(id: string): Observable { + return this.rest.request({ method: 'DELETE', - url: `/api/app/book/${id}`, - }; - - return this.rest.request(request); + url: `/api/app/book/${id}` + }); } ``` -### State Definitions +#### DeleteBook Action -Add an action named `BooksDelete` to `books.actions.ts` +Add an action named `DeleteBook` to `books.actions.ts`: ```typescript export class DeleteBook { @@ -517,7 +504,7 @@ export class DeleteBook { } ``` -Then, open the `books.state.ts` and add the `delete` method that will listen to a `CreateUpdateBook` action to create a book +Open the `books.state.ts` and add the `delete` method that will listen to the `DeleteBook` action to delete a book: ```typescript import { ... , DeleteBook } from '../actions/books.actions'; @@ -528,11 +515,12 @@ delete({ dispatch }: StateContext, { id }: DeleteBook) { } ``` -TODO: description?? +* Added `DeleteBook` to the import list. +* Uses `bookService` to delete the book. -### Add a Delete Button +#### Add a Delete Button -Open `book-list.component.html` and modify the `ngbDropdownMenu` for add the delete button as shown below: +Open `book-list.component.html` and modify the `ngbDropdownMenu` to add the delete button as shown below: ```html
@@ -543,13 +531,13 @@ Open `book-list.component.html` and modify the `ngbDropdownMenu` for add the del
``` -The final actions dropdown UI looks like this: +The final actions dropdown UI looks like below: ![bookstore-final-actions-dropdown](images/bookstore-final-actions-dropdown.png) -### Open Confirmation Popup +#### Delete Confirmation Dialog -Open `book-list.component.ts` and inject the `ConfirmationService` for show confirmation popup. +Open `book-list.component.ts` and inject the `ConfirmationService`. ```typescript import { ConfirmationService } from '@abp/ng.theme.shared'; @@ -560,7 +548,9 @@ constructor( ) ``` -Add the following method to `BookListComponent`. +> `ConfirmationService` is a simple service provided by ABP framework that internally uses the PrimeNG. + +Add a delete method to the `BookListComponent`: ```typescript import { ... , DeleteBook } from '../../store/actions'; @@ -577,10 +567,10 @@ delete(id: string, name: string) { } ``` -The `delete` method shows confirmation popup and listens to them. When close the popup, the subscribe block runs. If confirmed this popup, it will dispatch the `DeleteBook` action. - -The confirmation popup looks like this: +The `delete` method shows a confirmation popup and subscribes for the user response. `DeleteBook` action dispatched only if user clicks to the `Yes` button. The confirmation popup looks like below: ![bookstore-confirmation-popup](images/bookstore-confirmation-popup.png) -TODO: End +### Next Part + +See the [next part](Part-III.md) of this tutorial. \ No newline at end of file diff --git a/docs/en/Tutorials/Angular/Part-III.md b/docs/en/Tutorials/Angular/Part-III.md new file mode 100644 index 0000000000..ffc79de5b1 --- /dev/null +++ b/docs/en/Tutorials/Angular/Part-III.md @@ -0,0 +1,178 @@ +## ASP.NET Core MVC Tutorial - Part III + +### About this Tutorial + +This is the third part of the Angular tutorial series. See all parts: + +- [Part I: Create the project and a book list page](Part-I.md) +- [Part II: Create, Update and Delete books](Part-II.md) +- **Part III: Integration Tests (this tutorial)** + +You can access to the **source code** of the application from the [GitHub repository](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb). + +### Test Projects in the Solution + +There are multiple test projects in the solution: + +![bookstore-test-projects-v2](images/bookstore-test-projects-v2.png) + +Each project is used to test the related application project. Test projects use the following libraries for testing: + +* [xunit](https://xunit.github.io/) as the main test framework. +* [Shoudly](http://shouldly.readthedocs.io/en/latest/) as an assertion library. +* [NSubstitute](http://nsubstitute.github.io/) as a mocking library. + +### Adding Test Data + +Startup template contains the `BookStoreTestDataSeedContributor` class in the `Acme.BookStore.TestBase` project that creates some data to run tests on. + +Change the `BookStoreTestDataSeedContributor` class as show below: + +````C# +using System; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; + +namespace Acme.BookStore +{ + public class BookStoreTestDataSeedContributor + : IDataSeedContributor, ITransientDependency + { + private readonly IRepository _bookRepository; + private readonly IGuidGenerator _guidGenerator; + + public BookStoreTestDataSeedContributor( + IRepository bookRepository, + IGuidGenerator guidGenerator) + { + _bookRepository = bookRepository; + _guidGenerator = guidGenerator; + } + + public async Task SeedAsync(DataSeedContext context) + { + await _bookRepository.InsertAsync( + new Book + { + Id = _guidGenerator.Create(), + Name = "Test book 1", + Type = BookType.Fantastic, + PublishDate = new DateTime(2015, 05, 24), + Price = 21 + } + ); + + await _bookRepository.InsertAsync( + new Book + { + Id = _guidGenerator.Create(), + Name = "Test book 2", + Type = BookType.Science, + PublishDate = new DateTime(2014, 02, 11), + Price = 15 + } + ); + } + } +} +```` + +* Injected `IRepository` and used it in the `SeedAsync` to create two book entities as the test data. +* Used `IGuidGenerator` service to create GUIDs. While `Guid.NewGuid()` would perfectly work for testing, `IGuidGenerator` has additional features especially important while using real databases (see the [Guid generation document](../../Guid-Generation.md) for more). + +### Testing the BookAppService + +Create a test class named `BookAppService_Tests` in the `Acme.BookStore.Application.Tests` project: + +````C# +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Application.Dtos; +using Xunit; + +namespace Acme.BookStore +{ + public class BookAppService_Tests : BookStoreApplicationTestBase + { + private readonly IBookAppService _bookAppService; + + public BookAppService_Tests() + { + _bookAppService = GetRequiredService(); + } + + [Fact] + public async Task Should_Get_List_Of_Books() + { + //Act + var result = await _bookAppService.GetListAsync( + new PagedAndSortedResultRequestDto() + ); + + //Assert + result.TotalCount.ShouldBeGreaterThan(0); + result.Items.ShouldContain(b => b.Name == "Test book 1"); + } + } +} +```` + +* `Should_Get_List_Of_Books` test simply uses `BookAppService.GetListAsync` method to get and check the list of users. + +Add a new test that creates a valid new book: + +````C# +[Fact] +public async Task Should_Create_A_Valid_Book() +{ + //Act + var result = await _bookAppService.CreateAsync( + new CreateUpdateBookDto + { + Name = "New test book 42", + Price = 10, + PublishDate = DateTime.Now, + Type = BookType.ScienceFiction + } + ); + + //Assert + result.Id.ShouldNotBe(Guid.Empty); + result.Name.ShouldBe("New test book 42"); +} +```` + +Add a new test that tries to create an invalid book and fails: + +````C# +[Fact] +public async Task Should_Not_Create_A_Book_Without_Name() +{ + var exception = await Assert.ThrowsAsync(async () => + { + await _bookAppService.CreateAsync( + new CreateUpdateBookDto + { + Name = "", + Price = 10, + PublishDate = DateTime.Now, + Type = BookType.ScienceFiction + } + ); + }); + + exception.ValidationErrors + .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name")); +} +```` + +* Since the `Name` is empty, ABP throws an `AbpValidationException`. + +Open the **Test Explorer Window** (use Test -> Windows -> Test Explorer menu if it is not visible) and **Run All** tests: + +![bookstore-appservice-tests](images/bookstore-appservice-tests.png) + +Congratulations, green icons show that tests have been successfully passed! \ No newline at end of file diff --git a/docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png b/docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png new file mode 100644 index 0000000000000000000000000000000000000000..8701164d7514d15b27b6f83dfde1536bc38f5c58 GIT binary patch literal 6864 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 Date: Thu, 15 Aug 2019 11:07:04 +0300 Subject: [PATCH 2/9] Added tests to bookstore angular sample --- build-all.ps1 | 1 - docs/en/Tutorials/Angular/Part-III.md | 4 +- .../images/bookstore-test-projects-v2.png | Bin 6864 -> 0 bytes .../images/bookstore-test-projects-v3.png | Bin 0 -> 18079 bytes .../BookAppService_Tests.cs | 72 ++++++++++++++++++ .../BookStoreTestDataSeedContributor.cs | 43 +++++++++-- 6 files changed, 112 insertions(+), 8 deletions(-) delete mode 100644 docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png create mode 100644 docs/en/Tutorials/Angular/images/bookstore-test-projects-v3.png create mode 100644 samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Application.Tests/BookAppService_Tests.cs diff --git a/build-all.ps1 b/build-all.ps1 index 023cbdeb4a..649abc5f8c 100644 --- a/build-all.ps1 +++ b/build-all.ps1 @@ -21,7 +21,6 @@ $solutionPaths = ( "modules/client-simulation", "templates/module/aspnet-core", "templates/app/aspnet-core", - "samples/MicroserviceDemo", "abp_io/AbpIoLocalization" ) diff --git a/docs/en/Tutorials/Angular/Part-III.md b/docs/en/Tutorials/Angular/Part-III.md index ffc79de5b1..93934da396 100644 --- a/docs/en/Tutorials/Angular/Part-III.md +++ b/docs/en/Tutorials/Angular/Part-III.md @@ -8,13 +8,13 @@ This is the third part of the Angular tutorial series. See all parts: - [Part II: Create, Update and Delete books](Part-II.md) - **Part III: Integration Tests (this tutorial)** -You can access to the **source code** of the application from the [GitHub repository](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb). +This part covers the **server side** tests. You can access to the **source code** of the application from the [GitHub repository](https://github.com/abpframework/abp/tree/dev/samples/BookStore-Angular-MongoDb). ### Test Projects in the Solution There are multiple test projects in the solution: -![bookstore-test-projects-v2](images/bookstore-test-projects-v2.png) +![bookstore-test-projects](images/bookstore-test-projects-v3.png) Each project is used to test the related application project. Test projects use the following libraries for testing: diff --git a/docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png b/docs/en/Tutorials/Angular/images/bookstore-test-projects-v2.png deleted file mode 100644 index 8701164d7514d15b27b6f83dfde1536bc38f5c58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6864 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 P&w!-F<;5yR3(); + } + + [Fact] + public async Task Should_Get_List_Of_Books() + { + //Act + var result = await _bookAppService.GetListAsync( + new PagedAndSortedResultRequestDto() + ); + + //Assert + result.TotalCount.ShouldBeGreaterThan(0); + result.Items.ShouldContain(b => b.Name == "Test book 1"); + } + + [Fact] + public async Task Should_Create_A_Valid_Book() + { + //Act + var result = await _bookAppService.CreateAsync( + new CreateUpdateBookDto + { + Name = "New test book 42", + Price = 10, + PublishDate = DateTime.Now, + Type = BookType.ScienceFiction + } + ); + + //Assert + result.Id.ShouldNotBe(Guid.Empty); + result.Name.ShouldBe("New test book 42"); + } + + [Fact] + public async Task Should_Not_Create_A_Book_Without_Name() + { + var exception = await Assert.ThrowsAsync(async () => + { + await _bookAppService.CreateAsync( + new CreateUpdateBookDto + { + Name = "", + Price = 10, + PublishDate = DateTime.Now, + Type = BookType.ScienceFiction + } + ); + }); + + exception.ValidationErrors + .ShouldContain(err => err.MemberNames.Any(mem => mem == "Name")); + } + } +} \ No newline at end of file diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/BookStoreTestDataSeedContributor.cs b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/BookStoreTestDataSeedContributor.cs index 5712782714..116e25ed25 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/BookStoreTestDataSeedContributor.cs +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/BookStoreTestDataSeedContributor.cs @@ -1,16 +1,49 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; namespace Acme.BookStore { - public class BookStoreTestDataSeedContributor : IDataSeedContributor, ITransientDependency + public class BookStoreTestDataSeedContributor + : IDataSeedContributor, ITransientDependency { - public Task SeedAsync(DataSeedContext context) + private readonly IRepository _bookRepository; + private readonly IGuidGenerator _guidGenerator; + + public BookStoreTestDataSeedContributor( + IRepository bookRepository, + IGuidGenerator guidGenerator) + { + _bookRepository = bookRepository; + _guidGenerator = guidGenerator; + } + + public async Task SeedAsync(DataSeedContext context) { - /* Seed additional test data... */ + await _bookRepository.InsertAsync( + new Book + { + Id = _guidGenerator.Create(), + Name = "Test book 1", + Type = BookType.Fantastic, + PublishDate = new DateTime(2015, 05, 24), + Price = 21 + } + ); - return Task.CompletedTask; + await _bookRepository.InsertAsync( + new Book + { + Id = _guidGenerator.Create(), + Name = "Test book 2", + Type = BookType.Science, + PublishDate = new DateTime(2014, 02, 11), + Price = 15 + } + ); } } } \ No newline at end of file From dfcebaa74bfae0769de622a94b206fab98f8bbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 15 Aug 2019 11:08:23 +0300 Subject: [PATCH 3/9] Update nuget packages. --- .../Acme.BookStore.Application.Tests.csproj | 2 +- .../Acme.BookStore.Domain.Tests.csproj | 2 +- .../Acme.BookStore.MongoDB.Tests.csproj | 2 +- .../Acme.BookStore.TestBase/Acme.BookStore.TestBase.csproj | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj index bedb0062f2..83c6786ceb 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Application.Tests/Acme.BookStore.Application.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Domain.Tests/Acme.BookStore.Domain.Tests.csproj b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Domain.Tests/Acme.BookStore.Domain.Tests.csproj index e2c95c5093..c97fc84230 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Domain.Tests/Acme.BookStore.Domain.Tests.csproj +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.Domain.Tests/Acme.BookStore.Domain.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/Acme.BookStore.MongoDB.Tests.csproj b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/Acme.BookStore.MongoDB.Tests.csproj index 7a3f6b0867..5554dd39aa 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/Acme.BookStore.MongoDB.Tests.csproj +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/Acme.BookStore.MongoDB.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/Acme.BookStore.TestBase.csproj b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/Acme.BookStore.TestBase.csproj index c27cc7e09a..e72ffae2de 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/Acme.BookStore.TestBase.csproj +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.TestBase/Acme.BookStore.TestBase.csproj @@ -15,8 +15,8 @@ - - + + From 99a584ecb88e7a0c9bf44ef71930e9efe0cb9b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 15 Aug 2019 11:20:21 +0300 Subject: [PATCH 4/9] Add test explorer image --- docs/en/Tutorials/Angular/Part-III.md | 2 +- .../Angular/images/bookstore-test-explorer.png | Bin 0 -> 46788 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/en/Tutorials/Angular/images/bookstore-test-explorer.png diff --git a/docs/en/Tutorials/Angular/Part-III.md b/docs/en/Tutorials/Angular/Part-III.md index 93934da396..0da85f0751 100644 --- a/docs/en/Tutorials/Angular/Part-III.md +++ b/docs/en/Tutorials/Angular/Part-III.md @@ -173,6 +173,6 @@ public async Task Should_Not_Create_A_Book_Without_Name() Open the **Test Explorer Window** (use Test -> Windows -> Test Explorer menu if it is not visible) and **Run All** tests: -![bookstore-appservice-tests](images/bookstore-appservice-tests.png) +![bookstore-appservice-tests](images/bookstore-test-explorer.png) Congratulations, green icons show that tests have been successfully passed! \ No newline at end of file diff --git a/docs/en/Tutorials/Angular/images/bookstore-test-explorer.png b/docs/en/Tutorials/Angular/images/bookstore-test-explorer.png new file mode 100644 index 0000000000000000000000000000000000000000..06e9e7d331019e510bf8885abe99511c83b11cba GIT binary patch literal 46788 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 Date: Thu, 15 Aug 2019 11:33:20 +0300 Subject: [PATCH 5/9] Update BookStoreMongoDbTestModule.cs --- .../MongoDb/BookStoreMongoDbTestModule.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/MongoDb/BookStoreMongoDbTestModule.cs b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/MongoDb/BookStoreMongoDbTestModule.cs index c59bf2452c..d45f3ea02f 100644 --- a/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/MongoDb/BookStoreMongoDbTestModule.cs +++ b/samples/BookStore-Angular-MongoDb/aspnet-core/test/Acme.BookStore.MongoDB.Tests/MongoDb/BookStoreMongoDbTestModule.cs @@ -1,6 +1,5 @@ using System; using Mongo2Go; -using Volo.Abp; using Volo.Abp.Data; using Volo.Abp.Modularity; @@ -12,21 +11,18 @@ namespace Acme.BookStore.MongoDB )] public class BookStoreMongoDbTestModule : AbpModule { - private MongoDbRunner _mongoDbRunner; + private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); public override void ConfigureServices(ServiceConfigurationContext context) { - _mongoDbRunner = MongoDbRunner.Start(); + var connectionString = MongoDbRunner.ConnectionString.EnsureEndsWith('/') + + "BookStore_" + + Guid.NewGuid().ToString("N"); Configure(options => { - options.ConnectionStrings.Default = _mongoDbRunner.ConnectionString.EnsureEndsWith('/') + "BookStore"; + options.ConnectionStrings.Default = connectionString; }); } - - public override void OnApplicationShutdown(ApplicationShutdownContext context) - { - _mongoDbRunner.Dispose(); - } } } \ No newline at end of file From 0614a6871014b24b636a402b190dd2325e5bd6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 15 Aug 2019 11:41:59 +0300 Subject: [PATCH 6/9] #1632 MongoDB test problems & optimization --- .../MongoDb/MyProjectNameMongoDbTestModule.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.MongoDB.Tests/MongoDb/MyProjectNameMongoDbTestModule.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.MongoDB.Tests/MongoDb/MyProjectNameMongoDbTestModule.cs index 71be56844c..7141e66167 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.MongoDB.Tests/MongoDb/MyProjectNameMongoDbTestModule.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.MongoDB.Tests/MongoDb/MyProjectNameMongoDbTestModule.cs @@ -1,6 +1,5 @@ using System; using Mongo2Go; -using Volo.Abp; using Volo.Abp.Data; using Volo.Abp.Modularity; @@ -12,21 +11,18 @@ namespace MyCompanyName.MyProjectName.MongoDB )] public class MyProjectNameMongoDbTestModule : AbpModule { - private MongoDbRunner _mongoDbRunner; + private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start(); public override void ConfigureServices(ServiceConfigurationContext context) { - _mongoDbRunner = MongoDbRunner.Start(); + var connectionString = MongoDbRunner.ConnectionString.EnsureEndsWith('/') + + "MyProjectName_" + + Guid.NewGuid().ToString("N"); Configure(options => { - options.ConnectionStrings.Default = _mongoDbRunner.ConnectionString.EnsureEndsWith('/') + "MyProjectName"; + options.ConnectionStrings.Default = connectionString; }); } - - public override void OnApplicationShutdown(ApplicationShutdownContext context) - { - _mongoDbRunner.Dispose(); - } } } \ No newline at end of file From 5e0b014c51f8cdea1d590e3d1fcdacef7a66fa62 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 15 Aug 2019 13:00:34 +0300 Subject: [PATCH 7/9] feature(theme-shared): add disabled input to button component --- .../identity/src/lib/components/users/users.component.html | 1 + .../src/lib/components/button/button.component.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index df4b6a2eb5..9f52238aee 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -188,6 +188,7 @@ requestURLContainSearchValue="users" iconClass="fa fa-check" (click)="save()" + [disabled]="form.invalid" >{{ 'AbpIdentity::Save' | abpLocalization }}
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts index 86ef5f2bd4..20e2d92e98 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts @@ -6,7 +6,7 @@ import { filter } from 'rxjs/operators'; @Component({ selector: 'abp-button', template: ` - `, @@ -24,6 +24,9 @@ export class ButtonComponent implements OnInit { @Input() loading: boolean = false; + @Input() + disabled: boolean = false; + @Input() requestType: string | string[]; From 88214d752196dc9b95f612c4f883cc035073f479 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Thu, 15 Aug 2019 13:01:40 +0300 Subject: [PATCH 8/9] feature(theme-shared): add busy input to modal add abp-button handler for loading refactor esc listener --- .../lib/components/modal/modal.component.html | 3 +- .../lib/components/modal/modal.component.ts | 46 +++++++++++-------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html index 559bc6b429..48027b54a4 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/modal/modal.component.html @@ -1,6 +1,7 @@