From ff6038d72d6df1dd07abcf28efd2b3f2677e4e00 Mon Sep 17 00:00:00 2001 From: Shuaib Hasan Akib Date: Sat, 30 Aug 2025 11:48:22 +0600 Subject: [PATCH] docs(docs-infra): remove deprecated module and add test cases (#63497) PR Close #63497 --- .../services/content-loader.service.spec.ts | 182 +++++++++++++++++- 1 file changed, 176 insertions(+), 6 deletions(-) diff --git a/adev/src/app/core/services/content-loader.service.spec.ts b/adev/src/app/core/services/content-loader.service.spec.ts index 1ab71a44d34..3b1ce041deb 100644 --- a/adev/src/app/core/services/content-loader.service.spec.ts +++ b/adev/src/app/core/services/content-loader.service.spec.ts @@ -6,23 +6,193 @@ * found in the LICENSE file at https://angular.dev/license */ +import {HttpErrorResponse, provideHttpClient} from '@angular/common/http'; +import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; import {TestBed} from '@angular/core/testing'; - +import {DocContent} from '@angular/docs'; import {ContentLoader} from './content-loader.service'; -import {HttpClientTestingModule} from '@angular/common/http/testing'; describe('ContentLoader', () => { let service: ContentLoader; + let httpTestingController: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ - providers: [ContentLoader], - imports: [HttpClientTestingModule], + providers: [ContentLoader, provideHttpClient(), provideHttpClientTesting()], }); + service = TestBed.inject(ContentLoader); + httpTestingController = TestBed.inject(HttpTestingController); }); - it('should be created', () => { - expect(service).toBeTruthy(); + afterEach(() => { + httpTestingController.verify(); + }); + + describe('getContent', () => { + it('should fetch content successfully', async () => { + const path = 'test-document.md.html'; + const mockContent = '

Test Document

'; + const expectedDocContent: DocContent = { + contents: mockContent, + id: path, + }; + + const contentPromise = service.getContent(path); + + const req = httpTestingController.expectOne(`assets/content/${path}`); + expect(req.request.method).toEqual('GET'); + expect(req.request.responseType).toEqual('text'); + req.flush(mockContent); + + const result = await contentPromise; + expect(result).toEqual(expectedDocContent); + }); + + it('should add .md.html extension when path has no extension', async () => { + const path = 'test-document'; + const expectedPath = 'test-document.md.html'; + const mockContent = '

Test Document

'; + + const contentPromise = service.getContent(path); + + const req = httpTestingController.expectOne(`assets/content/${expectedPath}`); + expect(req.request.method).toEqual('GET'); + req.flush(mockContent); + + const result = await contentPromise; + expect(result.id).toEqual(expectedPath); + expect(result.contents).toEqual(mockContent); + }); + + it('should not modify path when it already has an extension', async () => { + const path = 'test-document.html'; + const mockContent = '

Test Document

'; + + const contentPromise = service.getContent(path); + + const req = httpTestingController.expectOne(`assets/content/${path}`); + req.flush(mockContent); + + const result = await contentPromise; + expect(result.id).toEqual(path); + }); + + it('should cache content and return cached version on subsequent calls', async () => { + const path = 'cached-document.md.html'; + const mockContent = '

Cached Document

'; + + // First call + const firstCallPromise = service.getContent(path); + const req1 = httpTestingController.expectOne(`assets/content/${path}`); + req1.flush(mockContent); + const firstResult = await firstCallPromise; + + // Second call - should use cache, no HTTP request + const secondResult = await service.getContent(path); + + expect(firstResult).toEqual(secondResult); + expect(firstResult.contents).toEqual(mockContent); + httpTestingController.expectNone(`assets/content/${path}`); + }); + + it('should handle 404 errors and keep them in cache', async () => { + const path = 'non-existent.md.html'; + + const contentPromise = service.getContent(path); + + const req = httpTestingController.expectOne(`assets/content/${path}`); + req.flush('Not Found', {status: 404, statusText: 'Not Found'}); + + try { + await contentPromise; + fail('Expected promise to be rejected'); + } catch (error) { + expect(error).toBeInstanceOf(HttpErrorResponse); + expect((error as HttpErrorResponse).status).toBe(404); + } + + // Second call should also fail without making another HTTP request + // because 404 errors are cached + try { + await service.getContent(path); + fail('Expected second call to be rejected'); + } catch (error) { + expect(error).toBeInstanceOf(HttpErrorResponse); + expect((error as HttpErrorResponse).status).toBe(404); + } + httpTestingController.expectNone(`assets/content/${path}`); + }); + + it('should not cache non-404 errors and retry on subsequent calls', async () => { + const path = 'server-error.md.html'; + + // First call - server error + const firstCallPromise = service.getContent(path); + const req1 = httpTestingController.expectOne(`assets/content/${path}`); + req1.flush('Server Error', {status: 500, statusText: 'Internal Server Error'}); + + try { + await firstCallPromise; + fail('Expected first call to be rejected'); + } catch (error) { + expect(error).toBeInstanceOf(HttpErrorResponse); + expect((error as HttpErrorResponse).status).toBe(500); + } + + // Second call should make another HTTP request since 500 errors are not cached + const secondCallPromise = service.getContent(path); + const req2 = httpTestingController.expectOne(`assets/content/${path}`); + req2.flush('Success content'); + + const result = await secondCallPromise; + expect(result.contents).toEqual('Success content'); + }); + + it('should handle network errors and not cache them', async () => { + const path = 'network-error.md.html'; + + // First call - network error + const firstCallPromise = service.getContent(path); + const req1 = httpTestingController.expectOne(`assets/content/${path}`); + req1.error(new ProgressEvent('Network error')); + + try { + await firstCallPromise; + fail('Expected first call to be rejected'); + } catch (error) { + expect(error).toBeInstanceOf(HttpErrorResponse); + } + + // Second call should make another HTTP request since network errors are not cached + const secondCallPromise = service.getContent(path); + const req2 = httpTestingController.expectOne(`assets/content/${path}`); + req2.flush('Success after network error'); + + const result = await secondCallPromise; + expect(result.contents).toEqual('Success after network error'); + }); + + it('should handle paths with different extensions correctly', async () => { + const testCases = [ + {input: 'document.txt', expected: 'document.txt'}, + {input: 'document.json', expected: 'document.json'}, + {input: 'document.xml', expected: 'document.xml'}, + {input: 'document', expected: 'document.md.html'}, + ]; + + for (const testCase of testCases) { + const mockContent = `Content for ${testCase.input}`; + + const contentPromise = service.getContent(testCase.input); + + const req = httpTestingController.expectOne(`assets/content/${testCase.expected}`); + req.flush(mockContent); + + const result = await contentPromise; + expect(result.id).toEqual(testCase.expected); + expect(result.contents).toEqual(mockContent); + } + }); }); });