feat: Add newProjectConfigureHttpApiModule for API configuration and localization

feat: Implement SampleAppServiceTests for application service testing

feat: Create newProjectConfigureApplicationTests project for application layer tests

feat: Establish newProjectConfigureDomainTests project for domain layer tests

feat: Introduce Entity Framework Core tests for the newProjectConfigure application

feat: Develop console test application for HTTP API client demonstration

feat: Implement FakeCurrentPrincipalAccessor for testing purposes

chore: Set up test base classes and data seed contributors for consistent testing environment
This commit is contained in:
sayan.kolay committed 2026-08-31 16:18:47 +05:30
1 parent 7909179fca
commit b6f2213ccf
279 files changed
+39466

No files matched your search

+281
View File
@@ -0,0 +1,281 @@
<div class="row mb-3">
<div class="col-xl-6 col-12 d-flex">
<div class="card h-lg-100 w-100 overflow-hidden">
<div class="card-body">
<div class="starting-content">
@if(!hasLoggedIn){
<h3>Welcome</h3>
<p class="lead text-muted mb-2">
{{ '::LongWelcomeMessage' | abpLocalization }}
</p>
<a (click)="login()" class="px-4 btn btn-primary mb-4" role="button"><i class="fa fa-sign-in"></i> {{
'AbpAccount::Login' | abpLocalization }}</a>
}
<h3>Getting Started</h3>
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
description:
'Learn how to create and run a new web application using the application startup template.',
href: 'https://abp.io/docs/latest/get-started',
label: 'Getting Started'
}
}
"></ng-container>
<h4>Web Application Development Tutorial</h4>
<ng-container *ngTemplateOutlet="
startingContentTemplate;
context: {
$implicit: {
description:
'Learn how to build an ABP based web application named Acme.BookStore.',
href: 'https://abp.io/docs/latest/tutorials/book-store/part-01?UI=NG&DB=EF',
label: 'Explore Tutorial'
}
}
"></ng-container>
<h4>Customize Lepton Theme</h4>
<p class="text-muted mb-2">Learn how to customize LeptonX Theme as you wish.</p>
<a href="https://abp.io/docs/latest/framework/ui/angular/theming" class="btn btn-primary soft mb-5 mb-xl-0"
target="_blank">Customize Lepton</a>
</div>
<img class="card-bg-image" src="assets/images/getting-started/bg-01.png" />
</div>
</div>
</div>
<div class="col-xl-3 col-md-6 d-flex">
<div class="row">
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
label: 'Visit Support',
description:
'You can check for similar problems and solutions, or open a new topic to discuss your specific issue.',
href: 'https://abp.io/support/questions',
card: 'card overflow-hidden',
imgClass: '',
imgSrc: 'assets/images/getting-started/img-support.png',
logo: 'abp-support abp-logo mb-2'
}
}
"></ng-container>
<ng-container *ngTemplateOutlet="
visitLinkTemplate;
context: {
$implicit: {
label: 'Visit Blog',
description:
'You can find content on .NET development, cross-platform, ASP.NET application templates, ABP-related news, and more.',
href: 'https://abp.io/blog',
card: 'card h-md-100 overflow-hidden',
imgClass: 'margin-bottom: -24px',
imgSrc: 'assets/images/getting-started/img-blog.png',
logo: 'abp-blog abp-logo mb-2'
}
}
"></ng-container>
</div>
</div>
<div class="col-xl-3 col-md-6 d-flex">
<div class="card h-100 overflow-hidden">
<div class="card-body">
<div class="abp-community abp-logo mb-2"></div>
<p class="lead text-muted">
A unique community platform for
<span class="fw-bold">ABP Lovers!</span>
</p>
<p class="text-muted mb-2">
Explore all ABP users' experiences with the ABP Framework, discover articles and videos on
how to use ABP, and join raffles for a chance to win surprise gifts!
</p>
<a class="btn btn-brand soft mb-3" href="https://abp.io/community/" target="_blank">Join ABP Community</a>
</div>
<img class="mt-3" src="assets/images/getting-started/img-community.png" />
</div>
</div>
</div>
<div class="row">
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
title: 'More from ABP.IO',
items: [
{
iconType: 'icon',
style: true,
icon: 'bi bi-check fs-4',
iconClass: 'rounded-circle me-2 flex-center bg-brand soft',
title: 'Latest Release Logs',
link: 'https://github.com/abpframework/abp/releases',
},
{
iconType: 'icon',
style: true,
icon: 'bi bi-check fs-4',
iconClass: 'rounded-circle me-2 flex-center bg-brand soft',
title: 'Video Courses',
link: 'https://abp.io/video-courses/essentials',
},
{
iconType: 'icon',
style: true,
icon: 'bi bi-check fs-4',
iconClass: 'rounded-circle me-2 flex-center bg-brand soft',
title: 'Samples',
link: 'https://abp.io/docs/latest/Samples/Index',
},
{
iconType: 'icon',
style: true,
icon: 'bi bi-check fs-4',
iconClass: 'rounded-circle me-2 flex-center bg-brand soft',
title: 'Books',
link: 'https://abp.io/books',
},
{
iconType: 'icon',
style: true,
icon: 'bi bi-check fs-4',
iconClass: 'rounded-circle me-2 flex-center bg-brand soft',
title: 'FAQ',
link: 'https://abp.io/faq',
},
]
}
}
"></ng-container>
<div class="col-xl-6 col-lg-8 d-flex">
<div class="card">
<div class="card-body d-flex">
<div class="row align-items-center">
<div class="col-md-8">
<p class="text-muted mb-0">THE OFFICIAL GUIDE</p>
<h3>Mastering ABP Framework</h3>
<p class="text-muted">
Written by the creator of the ABP Framework, this book will help you gain a complete
understanding of the framework and modern web application development techniques.
</p>
<div class="d-md-flex mb-2 mb-md-0">
<a href="https://www.amazon.com/gp/product/B097Z2DM8Q" target="_blank"
class="btn btn-primary soft me-md-2 mb-2 mb-md-0">
Buy on Amazon US
</a>
<a href="https://www.packtpub.com/product/mastering-abp-framework/9781801079242" target="_blank"
class="btn btn-primary soft mb-2 mb-md-0">
Buy on PACKT
</a>
</div>
</div>
<div class="col">
<img src="assets/images/getting-started/book.png" />
</div>
</div>
</div>
</div>
</div>
<ng-container *ngTemplateOutlet="
tableTemplate;
context: {
$implicit: {
title: 'Follow us on Social Media',
items: [
{
title: 'X.com',
icon: 'logo-x me-2',
link: 'https://twitter.com/abpframework'
},
{
iconType: 'image',
icon: 'assets/images/getting-started/discord.svg',
title: 'Discord',
link: 'https://abp.io/community/discord'
},
{
iconType: 'image',
icon: 'assets/images/getting-started/stack-overflow.svg',
title: 'Stack Overflow',
link: 'https://stackoverflow.com/questions/tagged/abp'
},
{
iconType: 'image',
icon: 'assets/images/getting-started/youtube.svg',
title: 'YouTube',
link: 'https://www.youtube.com/@Volosoft'
},
{
iconType: 'image',
icon: 'assets/images/getting-started/instagram.svg',
title: 'Instagram',
link: 'https://www.instagram.com/abpframework/'
}
]
}
}
"></ng-container>
</div>
<ng-template #startingContentTemplate let-context>
<p class="lead text-muted mb-2" [innerHTML]="context.description"></p>
<a [href]="context.href" class="btn btn-brand mb-4" target="_blank">{{ context.label }}</a>
</ng-template>
<ng-template #visitLinkTemplate let-context>
<div class="col-12 d-flex">
<div [class]="context.card">
<div class="card-body pb-0">
<div [class]="context.logo"></div>
<p class="text-muted mb-2" [innerHTML]="context.description"></p>
<a [href]="context.href" class="btn btn-brand soft" target="_blank">{{ context.label }}</a>
<img [class]="context.imgClass" [src]="context.imgSrc" />
</div>
</div>
</div>
</ng-template>
<ng-template #tableTemplate let-context>
<div class="col-xl-3 col-lg-4">
<div class="card">
<div class="card-header">
<div class="card-title text-body">{{ context.title }}</div>
</div>
<div class="card-body pt-0">
<div class="table-responsive">
<table class="table mb-0">
<tbody>
@for(item of context.items; track $index; let last = $last){
<tr>
<td class="ps-0 d-flex" [class.border-bottom-0]="last">
@if(item.icon){
<div [class]="item.iconClass" [style]="item.style ? 'width: 20px; height: 20px' : ''">
@if(item.iconType === 'image'){
<img [src]="item.icon" class="me-2" />
}@else if(item.iconType === 'icon'){
<i [class]="item.icon"></i>
}@else{
<div [class]="item.icon"></div>
}
</div>
}
<div>{{ item.title }}</div>
</td>
<td class="text-end pe-0 opacity-25" [class.border-bottom-0]="last">
<a [href]="item.link" target="_blank">
<i class="bi bi-box-arrow-up-right text-dark"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</ng-template>
+25
View File
@@ -0,0 +1,25 @@
/* Styles for the home component */
.card-bg-image {
position: absolute;
width: 630px;
height: auto;
bottom: 0;
right: 0;
z-index: 1;
}
.starting-content {
position: relative;
z-index: 2;
}
@media (min-width: 1199px) {
.h-lg-100 {
height: 100% !important;
}
}
@media (min-width: 768px) {
.h-md-100 {
height: 100% !important;
}
}
@@ -0,0 +1,88 @@
import { CoreTestingModule } from "@abp/ng.core/testing";
import { ThemeSharedTestingModule } from "@abp/ng.theme.shared/testing";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { NgxValidateCoreModule } from "@ngx-validate/core";
import { HomeComponent } from "./home.component";
import { AuthService } from '@abp/ng.core';
import { vi } from 'vitest';
describe("HomeComponent", () => {
let fixture: ComponentFixture<HomeComponent>;
let mockAuthService: { isAuthenticated: boolean; navigateToLogin: ReturnType<typeof vi.fn> };
beforeEach(async () => {
mockAuthService = {
isAuthenticated: false,
navigateToLogin: vi.fn()
};
await TestBed.configureTestingModule({
imports: [
CoreTestingModule.withConfig(),
ThemeSharedTestingModule.withConfig(),
NgxValidateCoreModule,
HomeComponent
],
providers: [
{
provide: AuthService,
useValue: mockAuthService
}
],
}).compileComponents();
});
it("should be initiated", () => {
fixture = TestBed.createComponent(HomeComponent);
fixture.detectChanges();
expect(fixture.componentInstance).toBeTruthy();
});
describe('when login state is true', () => {
beforeEach(() => {
mockAuthService.isAuthenticated = true;
fixture = TestBed.createComponent(HomeComponent);
fixture.detectChanges();
});
it("hasLoggedIn should be true", () => {
expect(fixture.componentInstance.hasLoggedIn).toBe(true);
});
it("button should not be exists", () => {
const element = fixture.nativeElement;
const button = element.querySelector('[role="button"]');
expect(button).toBeNull();
});
});
describe('when login state is false', () => {
beforeEach(() => {
mockAuthService.isAuthenticated = false;
fixture = TestBed.createComponent(HomeComponent);
fixture.detectChanges();
});
it("hasLoggedIn should be false", () => {
expect(fixture.componentInstance.hasLoggedIn).toBe(false);
});
it("button should be exists", () => {
const element = fixture.nativeElement;
const button = element.querySelector('[role="button"]');
expect(button).toBeDefined();
});
describe('when button clicked', () => {
beforeEach(() => {
const element = fixture.nativeElement;
const button = element.querySelector('[role="button"]');
button.click();
});
it("navigateToLogin have been called", () => {
expect(mockAuthService.navigateToLogin).toHaveBeenCalled();
});
});
});
});
+92
View File
@@ -0,0 +1,92 @@
import { AuthService, LocalizationPipe } from '@abp/ng.core';
import { Component, inject } from '@angular/core';
import { NgTemplateOutlet } from '@angular/common';
import { FormFieldConfig } from '@abp/ng.components/dynamic-form';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
imports: [NgTemplateOutlet, LocalizationPipe],
})
export class HomeComponent {
private authService = inject(AuthService);
formFields: FormFieldConfig[] = [
{
key: 'firstName',
type: 'text',
label: 'First Name',
placeholder: 'Enter first name',
value: 'erdemc',
required: true,
validators: [
{ type: 'required', message: 'First name is required' },
{ type: 'minLength', value: 2, message: 'Minimum 2 characters required' },
],
gridSize: 6,
order: 1,
},
{
key: 'lastName',
type: 'text',
label: 'Last Name',
placeholder: 'Enter last name',
required: true,
validators: [{ type: 'required', message: 'Last name is required' }],
gridSize: 12,
order: 3,
},
{
key: 'email',
type: 'email',
label: 'Email Address',
placeholder: 'Enter email',
required: true,
validators: [
{ type: 'required', message: 'Email is required' },
{ type: 'email', message: 'Please enter a valid email' },
],
gridSize: 6,
order: 2,
},
{
key: 'userType',
type: 'select',
label: 'User Type',
required: true,
options: {
defaultValues: [
{ key: 'admin', value: 'Administrator' },
{ key: 'user', value: 'Regular User' },
{ key: 'guest', value: 'Guest User' },
],
},
validators: [{ type: 'required', message: 'Please select user type' }],
order: 4,
},
{
key: 'adminNotes',
type: 'textarea',
label: 'Admin Notes',
placeholder: 'Enter admin-specific notes',
conditionalLogic: [
{
dependsOn: 'userType',
condition: 'equals',
value: 'admin',
action: 'show',
},
],
order: 5,
},
];
get hasLoggedIn(): boolean {
return this.authService.isAuthenticated;
}
login() {
this.authService.navigateToLogin();
}
}
+9
View File
@@ -0,0 +1,9 @@
import { Routes } from '@angular/router';
export const homeRoutes: Routes = [
{
path: '',
pathMatch: 'full',
loadComponent: () => import('./home.component').then(m => m.HomeComponent),
},
];