Skip to content

Commit

Permalink
FE Unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
quanpham-axonivy committed Dec 25, 2024
1 parent ad40d8e commit fda4cfc
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ <h3 [lang]="languageService.selectedLanguage()" class="text-secondary">
[lang]="languageService.selectedLanguage()"
class="readme-content"
[data]="
getProductModuleContentValue(displayedTab)
getReadmeContentValue(displayedTab)
| multilingualism: languageService.selectedLanguage()
"></markdown>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReleasePreviewComponent } from './release-preview.component';
import { ReleasePreviewService } from './release-preview.service';
import { of, throwError } from 'rxjs';
import { LanguageService } from '../../core/services/language/language.service';
import { Language } from '../../shared/enums/language.enum';
import { TranslateModule } from '@ngx-translate/core';
import { MarkdownModule } from 'ngx-markdown';
import {
provideHttpClient,
withInterceptorsFromDi
} from '@angular/common/http';
import { provideHttpClientTesting } from '@angular/common/http/testing';

describe('ReleasePreviewComponent', () => {
let component: ReleasePreviewComponent;
let fixture: ComponentFixture<ReleasePreviewComponent>;
let releasePreviewService: ReleasePreviewService;
let languageService: jasmine.SpyObj<LanguageService>;

beforeEach(async () => {
const routingQueryParamServiceSpy = jasmine.createSpyObj(
'RoutingQueryParamService',
['getDesignerVersionFromSessionStorage', 'isDesignerEnv']
);

const languageServiceSpy = jasmine.createSpyObj('LanguageService', [
'selectedLanguage'
]);

await TestBed.configureTestingModule({
imports: [
ReleasePreviewComponent,
TranslateModule.forRoot(),
MarkdownModule.forRoot()
],
providers: [
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting(),
{
provide: LanguageService,
useValue: languageServiceSpy
}
]
}).compileComponents();
languageService = TestBed.inject(
LanguageService
) as jasmine.SpyObj<LanguageService>;
});

beforeEach(() => {
fixture = TestBed.createComponent(ReleasePreviewComponent);
component = fixture.componentInstance;
releasePreviewService = TestBed.inject(ReleasePreviewService);
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should set selected file on file selection', () => {
const mockFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
const event = {
target: {
files: [mockFile]
}
} as unknown as Event;

component.onFileSelected(event);

expect(component.selectedFile).toEqual(mockFile);
expect(component.isZipFile).toBeTrue();
expect(component.errorMessage).toBe('');
});

it('should display error for non-zip file', () => {
const mockFile = new File(['content'], 'test.txt', { type: 'text/plain' });
const event = {
target: {
files: [mockFile]
}
} as unknown as Event;

component.onFileSelected(event);

expect(component.selectedFile).toEqual(mockFile);
expect(component.isZipFile).toBeFalse();
expect(component.errorMessage).toBe('Please upload a valid ZIP file.');
});

it('should update tabs on valid response', () => {
const mockResponse = {
description: {
en: 'Description in English',
de: 'Beschreibung auf Deutsch'
},
setup: { en: 'Setup in English', de: 'Setup auf Deutsch' },
demo: { en: 'Demo in English', de: 'Demo auf Deutsch' }
};

component.updateTabs(mockResponse);

expect(component.tabs.length).toBe(3);
expect(component.tabs[0].label).toBe('Description');
expect(component.tabs[0].content).toBe('Description in English');
});

it('should handle file upload and call service', () => {
spyOn(releasePreviewService, 'extractZipDetails').and.callThrough();

const mockFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
component.selectedFile = mockFile;
component.isZipFile = true;

component.onSubmit();

expect(releasePreviewService.extractZipDetails).toHaveBeenCalledWith(
mockFile
);
});

it('should display error message on service error', () => {
spyOn(releasePreviewService, 'extractZipDetails').and.returnValue(
throwError(() => new Error('Service error'))
);

const mockFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
component.selectedFile = mockFile;
component.isZipFile = true;

component.onSubmit();

expect(component.errorMessage).toBe('Service error');
});

it('should filter tabs based on available content', () => {
spyOn(component, 'getContent').and.callFake(tab => tab === 'description');

const displayedTabs = component.getDisplayedTabsSignal();

expect(displayedTabs.length).toBe(1);
expect(displayedTabs[0].value).toBe('description');
});

it('should return true for description when in DE language it is not null and not undefined and not empty', () => {
component.readmeContent.set({
description: { en: 'Description content' },
setup: {},
demo: {}
});

const selectedLanguage = Language.DE;

languageService.selectedLanguage.and.returnValue(
selectedLanguage
);

expect(component.getContent('description')).toBeTrue();
expect(component.getContent('setup')).toBeFalse();
expect(component.getContent('demo')).toBeFalse();
});

it('should handle successful file upload', () => {
const mockResponse = {
description: { en: 'Description content' },
setup: { en: 'Setup content' },
demo: { en: 'Demo content' }
};
spyOn(releasePreviewService, 'extractZipDetails').and.returnValue(
of(mockResponse)
);

component.selectedFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
component.isZipFile = true;
component.handlePreviewPage();

expect(releasePreviewService.extractZipDetails).toHaveBeenCalledWith(
component.selectedFile
);
expect(component.readmeContent()).toEqual(mockResponse);
expect(component.errorMessage).toBe('');
expect(component.loading).toBeFalse();
});

it('should handle file upload error', () => {
const error = { message: 'Upload failed' };
spyOn(releasePreviewService, 'extractZipDetails').and.returnValue(
throwError(() => error)
);

component.selectedFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
component.isZipFile = true;
component.handlePreviewPage();

expect(releasePreviewService.extractZipDetails).toHaveBeenCalledWith(
component.selectedFile
);
expect(component.errorMessage).toBe('Upload failed');
expect(component.loading).toBeFalse();
});

it('should update tabs based on response', () => {
const mockResponse = {
description: { en: 'Description content' },
setup: { en: 'Setup content' },
demo: { en: 'Demo content' }
};

component.updateTabs(mockResponse);

expect(component.tabs.length).toBe(3);
expect(component.activeTab).toBe('description');
expect(component.tabs[0].content).toBe('Description content');
});

it('should set activeTab when setActiveTab is called', () => {
component.setActiveTab('setup');
expect(component.activeTab).toBe('setup');
});



});
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class ReleasePreviewComponent {
availableLanguages = ['en', 'de'];
selectedLanguage = 'en';
isZipFile = false;
productModuleContent: WritableSignal<ReleasePreviewData> = signal(
readmeContent: WritableSignal<ReleasePreviewData> = signal(
{} as ReleasePreviewData
);
languageService = inject(LanguageService);
Expand Down Expand Up @@ -110,7 +110,7 @@ export class ReleasePreviewComponent {
}
}

private handlePreviewPage(): void {
handlePreviewPage(): void {
if (!this.selectedFile) {
this.errorMessage = 'Please select a file to upload.';
return;
Expand All @@ -124,7 +124,7 @@ export class ReleasePreviewComponent {
this.releasePreviewService.extractZipDetails(this.selectedFile).subscribe({
next: response => {
this.loading = false;
this.productModuleContent.set(response);
this.readmeContent.set(response);
this.updateTabs(response);
},
error: error => {
Expand All @@ -146,7 +146,7 @@ export class ReleasePreviewComponent {
}

getContent(value: string): boolean {
const content = this.productModuleContent();
const content = this.readmeContent();

if (!content || Object.keys(content).length === 0) {
return false;
Expand Down Expand Up @@ -180,9 +180,9 @@ export class ReleasePreviewComponent {
return CommonUtils.getLabel(this.activeTab, PRODUCT_DETAIL_TABS);
}

getProductModuleContentValue(key: ItemDropdown): DisplayValue | null {
getReadmeContentValue(key: ItemDropdown): DisplayValue | null {
type tabName = 'description' | 'demo' | 'setup';
const value = key.value as tabName;
return this.productModuleContent()[value];
return this.readmeContent()[value];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { TestBed } from '@angular/core/testing';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { ReleasePreviewService } from './release-preview.service';
import { environment } from '../../../environments/environment';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { ReleasePreviewData } from '../../shared/models/release-preview-data.model';

describe('SecurityMonitorService', () => {
let service: ReleasePreviewService;
let httpMock: HttpTestingController;

const mockApiUrl = environment.apiUrl + '/api/release-preview';

beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ReleasePreviewService,
provideHttpClient(withInterceptorsFromDi()),
provideHttpClientTesting()
]
});
service = TestBed.inject(ReleasePreviewService);
httpMock = TestBed.inject(HttpTestingController);
});

afterEach(() => {
httpMock.verify();
});

it('should be created', () => {
expect(service).toBeTruthy();
});

it('should call API and return Readme data', () => {
const mockFile = new File(['content'], 'test.zip', {
type: 'application/zip'
});
const mockResponse: ReleasePreviewData = {
description: {
English: 'This is a description in English.',
Spanish: 'Esta es una descripción en español.',
French: 'Ceci est une description en français.'
},
setup: {
English: 'To set up the application, follow these steps...',
Spanish: 'Para configurar la aplicación, siga estos pasos...',
French: "Pour configurer l'application, suivez ces étapes..."
},
demo: {
English: 'To demo the app, use the following commands...',
Spanish:
'Para mostrar la aplicación, use los siguientes comandos...',
French:
"Pour démontrer l'application, utilisez les commandes suivantes..."
}
};

service.extractZipDetails(mockFile).subscribe(data => {
expect(data).toEqual(mockResponse);
});

const req = httpMock.expectOne(mockApiUrl);
expect(req.request.method).toBe('POST');

req.flush(mockResponse);
});
});

0 comments on commit fda4cfc

Please sign in to comment.