diff --git a/marketplace-ui/src/app/modules/release-preview/release-preview.component.html b/marketplace-ui/src/app/modules/release-preview/release-preview.component.html
index 810bca8a..8865d982 100644
--- a/marketplace-ui/src/app/modules/release-preview/release-preview.component.html
+++ b/marketplace-ui/src/app/modules/release-preview/release-preview.component.html
@@ -91,7 +91,7 @@
[lang]="languageService.selectedLanguage()"
class="readme-content"
[data]="
- getProductModuleContentValue(displayedTab)
+ getReadmeContentValue(displayedTab)
| multilingualism: languageService.selectedLanguage()
">
diff --git a/marketplace-ui/src/app/modules/release-preview/release-preview.component.spec.ts b/marketplace-ui/src/app/modules/release-preview/release-preview.component.spec.ts
index e69de29b..1bac76b5 100644
--- a/marketplace-ui/src/app/modules/release-preview/release-preview.component.spec.ts
+++ b/marketplace-ui/src/app/modules/release-preview/release-preview.component.spec.ts
@@ -0,0 +1,159 @@
+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;
+ let releasePreviewService: ReleasePreviewService;
+ let languageService: jasmine.SpyObj;
+
+ 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;
+ });
+
+ 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();
+ });
+
+ it('should check 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();
+ });
+
+ 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 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);
+ });
+
+ it('should set activeTab when setActiveTab is called', () => {
+ component.setActiveTab('setup');
+ expect(component.activeTab).toBe('setup');
+ });
+});
diff --git a/marketplace-ui/src/app/modules/release-preview/release-preview.component.ts b/marketplace-ui/src/app/modules/release-preview/release-preview.component.ts
index cbea55d7..85598017 100644
--- a/marketplace-ui/src/app/modules/release-preview/release-preview.component.ts
+++ b/marketplace-ui/src/app/modules/release-preview/release-preview.component.ts
@@ -41,14 +41,10 @@ const DEFAULT_ACTIVE_TAB = 'description';
})
export class ReleasePreviewComponent {
selectedFile: File | null = null;
- tabs: { label: string; content: string }[] = [];
- loading = false;
activeTab = DEFAULT_ACTIVE_TAB;
- errorMessage = '';
- availableLanguages = ['en', 'de'];
selectedLanguage = 'en';
isZipFile = false;
- productModuleContent: WritableSignal = signal(
+ readmeContent: WritableSignal = signal(
{} as ReleasePreviewData
);
languageService = inject(LanguageService);
@@ -71,65 +67,29 @@ export class ReleasePreviewComponent {
// Check if the selected file is a ZIP file
this.isZipFile =
file.type === 'application/zip' || file.name.endsWith('.zip');
-
- if (!this.isZipFile) {
- this.errorMessage = 'Please upload a valid ZIP file.';
- } else {
- this.errorMessage = '';
- }
}
}
onSubmit(): void {
- this.loading = true;
this.handlePreviewPage();
}
- setActiveTab(index: string): void {
- this.activeTab = index;
+ setActiveTab(tab: string): void {
+ this.activeTab = tab;
}
onTabChange(event: string) {
this.setActiveTab(event);
}
- updateTabs(response: ReleasePreviewData): void {
- if (response) {
- this.tabs = [
- {
- label: 'Description',
- content: response.description[this.selectedLanguage] || ''
- },
- {
- label: 'Setup',
- content: response.setup[this.selectedLanguage] || ''
- },
- { label: 'Demo', content: response.demo[this.selectedLanguage] || '' }
- ];
- this.activeTab = DEFAULT_ACTIVE_TAB;
- }
- }
-
- private handlePreviewPage(): void {
- if (!this.selectedFile) {
- this.errorMessage = 'Please select a file to upload.';
+ handlePreviewPage(): void {
+ if (!this.selectedFile || !this.isZipFile) {
return;
}
- if (!this.isZipFile) {
- this.errorMessage = 'Only ZIP files are allowed.';
- return;
- }
- this.errorMessage = '';
this.releasePreviewService.extractZipDetails(this.selectedFile).subscribe({
next: response => {
- this.loading = false;
- this.productModuleContent.set(response);
- this.updateTabs(response);
- },
- error: error => {
- this.loading = false;
- this.errorMessage = error.message || 'An error occurred.';
+ this.readmeContent.set(response);
}
});
}
@@ -146,7 +106,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;
@@ -180,9 +140,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];
}
}
diff --git a/marketplace-ui/src/app/modules/release-preview/release-preview.service.spec.ts b/marketplace-ui/src/app/modules/release-preview/release-preview.service.spec.ts
index e69de29b..15123da3 100644
--- a/marketplace-ui/src/app/modules/release-preview/release-preview.service.spec.ts
+++ b/marketplace-ui/src/app/modules/release-preview/release-preview.service.spec.ts
@@ -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);
+ });
+});
\ No newline at end of file