diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 70894e5431..272555df70 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -14,73 +14,75 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/test-utils'; -import { getManifestByReleaseLine, getManifestByVersion } from './manifest'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; +import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { getManifestByReleaseLine, getManifestByVersion } from './manifest'; -describe('getManifestByVersion', () => { +describe('Release Manifests', () => { const worker = setupServer(); setupRequestMockHandlers(worker); - it('should return a list of packages in a release', async () => { - worker.use( - rest.get('*/v1/releases/0.0.0/manifest.json', (_, res, ctx) => - res( - ctx.status(200), - ctx.json({ - packages: [{ name: '@backstage/core', version: '1.2.3' }], - }), + describe('getManifestByVersion', () => { + it('should return a list of packages in a release', async () => { + worker.use( + rest.get('*/v1/releases/0.0.0/manifest.json', (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + packages: [{ name: '@backstage/core', version: '1.2.3' }], + }), + ), ), - ), - rest.get('*/v1/releases/999.0.1/manifest.json', (_, res, ctx) => - res(ctx.status(404), ctx.json({})), - ), - ); + rest.get('*/v1/releases/999.0.1/manifest.json', (_, res, ctx) => + res(ctx.status(404), ctx.json({})), + ), + ); - const pkgs = await getManifestByVersion({ version: '0.0.0' }); - expect(pkgs.packages).toEqual([ - { - name: '@backstage/core', - version: '1.2.3', - }, - ]); + const pkgs = await getManifestByVersion({ version: '0.0.0' }); + expect(pkgs.packages).toEqual([ + { + name: '@backstage/core', + version: '1.2.3', + }, + ]); - await expect(getManifestByVersion({ version: '999.0.1' })).rejects.toThrow( - 'No release found for 999.0.1 version', - ); - }); -}); - -describe('getManifestByReleaseLine', () => { - const worker = setupServer(); - setupRequestMockHandlers(worker); - - it('should return a list of packages in a release', async () => { - worker.use( - rest.get('*/v1/tags/main/manifest.json', (_, res, ctx) => - res( - ctx.status(200), - ctx.json({ - packages: [{ name: '@backstage/core', version: '1.2.3' }], - }), - ), - ), - rest.get('*/v1/tags/foo/manifest.json', (_, res, ctx) => - res(ctx.status(404), ctx.json({})), - ), - ); - - const pkgs = await getManifestByReleaseLine({ releaseLine: 'main' }); - expect(pkgs.packages).toEqual([ - { - name: '@backstage/core', - version: '1.2.3', - }, - ]); - - await expect( - getManifestByReleaseLine({ releaseLine: 'foo' }), - ).rejects.toThrow("No 'foo' release line found"); + await expect( + getManifestByVersion({ version: '999.0.1' }), + ).rejects.toThrow('No release found for 999.0.1 version'); + }); + }); + + describe('getManifestByReleaseLine', () => { + it('should return a list of packages in a release', async () => { + worker.use( + rest.get( + 'https://versions.backstage.io/v1/tags/main/manifest.json', + (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + packages: [{ name: '@backstage/core', version: '1.2.3' }], + }), + ), + ), + rest.get( + 'https://versions.backstage.io/v1/tags/foo/manifest.json', + (_, res, ctx) => res(ctx.status(404), ctx.json({})), + ), + ); + + const pkgs = await getManifestByReleaseLine({ releaseLine: 'main' }); + expect(pkgs.packages).toEqual([ + { + name: '@backstage/core', + version: '1.2.3', + }, + ]); + + await expect( + getManifestByReleaseLine({ releaseLine: 'foo' }), + ).rejects.toThrow("No 'foo' release line found"); + }); }); }); diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts index 684d5729a2..3f1a857c4d 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.test.ts @@ -74,144 +74,145 @@ const expectedEntities: Entity[] = [ }, ]; -describe('DefaultTechDocsCollator with legacyPathCasing configuration', () => { - let mockDiscoveryApi: jest.Mocked; - let mockTokenManager: jest.Mocked; - let collator: DefaultTechDocsCollator; - +describe('TechDocs Collator', () => { const worker = setupServer(); setupRequestMockHandlers(worker); - beforeEach(() => { - mockDiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValue('http://test-backend'), - getExternalBaseUrl: jest.fn(), - }; - mockTokenManager = { - getToken: jest.fn().mockResolvedValue({ token: '' }), - authenticate: jest.fn(), - }; - const mockConfig = new ConfigReader({ - techdocs: { - legacyUseCaseSensitiveTripletPaths: true, - }, - }); - collator = DefaultTechDocsCollator.fromConfig(mockConfig, { - discovery: mockDiscoveryApi, - tokenManager: mockTokenManager, - logger, - legacyPathCasing: true, - }); - worker.use( - rest.get( - 'http://test-backend/static/docs/default/Component/test-entity-with-docs/search/search_index.json', - (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), - ), - rest.get('http://test-backend/entities', (_, res, ctx) => - res(ctx.status(200), ctx.json(expectedEntities)), - ), - ); - }); + describe('DefaultTechDocsCollator with legacyPathCasing configuration', () => { + let mockDiscoveryApi: jest.Mocked; + let mockTokenManager: jest.Mocked; + let collator: DefaultTechDocsCollator; - it('fetches from the configured catalog and tech docs services', async () => { - const documents = await collator.execute(); - expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('catalog'); - expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('techdocs'); - expect(documents).toHaveLength(mockSearchDocIndex.docs.length); - }); - - it('should create documents for each tech docs search index', async () => { - const documents = await collator.execute(); - const entity = expectedEntities[0]; - documents.forEach((document, idx) => { - expect(document).toMatchObject({ - title: mockSearchDocIndex.docs[idx].title, - location: `/docs/default/Component/${entity.metadata.name}/${mockSearchDocIndex.docs[idx].location}`, - text: mockSearchDocIndex.docs[idx].text, - namespace: 'default', - entityTitle: entity!.metadata.title, - componentType: entity!.spec!.type, - lifecycle: entity!.spec!.lifecycle, - owner: '', - kind: entity.kind, - name: entity.metadata.name, - }); - }); - }); -}); - -describe('DefaultTechDocsCollator', () => { - let mockDiscoveryApi: jest.Mocked; - let mockTokenManager: jest.Mocked; - let collator: DefaultTechDocsCollator; - - const worker = setupServer(); - setupRequestMockHandlers(worker); - beforeEach(() => { - mockDiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValue('http://test-backend'), - getExternalBaseUrl: jest.fn(), - }; - mockTokenManager = { - getToken: jest.fn().mockResolvedValue({ token: '' }), - authenticate: jest.fn(), - }; - collator = DefaultTechDocsCollator.fromConfig(new ConfigReader({}), { - discovery: mockDiscoveryApi, - tokenManager: mockTokenManager, - logger, - }); - - worker.use( - rest.get( - 'http://test-backend/static/docs/default/component/test-entity-with-docs/search/search_index.json', - (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), - ), - rest.get('http://test-backend/entities', (_, res, ctx) => - res(ctx.status(200), ctx.json(expectedEntities)), - ), - ); - }); - - it('should create documents for each tech docs search index', async () => { - const documents = await collator.execute(); - const entity = expectedEntities[0]; - documents.forEach((document, idx) => { - expect(document).toMatchObject({ - title: mockSearchDocIndex.docs[idx].title, - location: `/docs/default/component/${entity.metadata.name}/${mockSearchDocIndex.docs[idx].location}`, - text: mockSearchDocIndex.docs[idx].text, - namespace: 'default', - entityTitle: entity!.metadata.title, - componentType: entity!.spec!.type, - lifecycle: entity!.spec!.lifecycle, - owner: '', - kind: entity.kind.toLocaleLowerCase('en-US'), - name: entity.metadata.name.toLocaleLowerCase('en-US'), - authorization: { - resourceRef: `component:default/${entity.metadata.name}`, + beforeEach(() => { + mockDiscoveryApi = { + getBaseUrl: jest.fn().mockResolvedValue('http://test-backend'), + getExternalBaseUrl: jest.fn(), + }; + mockTokenManager = { + getToken: jest.fn().mockResolvedValue({ token: '' }), + authenticate: jest.fn(), + }; + const mockConfig = new ConfigReader({ + techdocs: { + legacyUseCaseSensitiveTripletPaths: true, }, }); + collator = DefaultTechDocsCollator.fromConfig(mockConfig, { + discovery: mockDiscoveryApi, + tokenManager: mockTokenManager, + logger, + legacyPathCasing: true, + }); + + worker.use( + rest.get( + 'http://test-backend/static/docs/default/Component/test-entity-with-docs/search/search_index.json', + (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), + ), + rest.get('http://test-backend/entities', (_, res, ctx) => + res(ctx.status(200), ctx.json(expectedEntities)), + ), + ); + }); + + it('fetches from the configured catalog and tech docs services', async () => { + const documents = await collator.execute(); + expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('catalog'); + expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('techdocs'); + expect(documents).toHaveLength(mockSearchDocIndex.docs.length); + }); + + it('should create documents for each tech docs search index', async () => { + const documents = await collator.execute(); + const entity = expectedEntities[0]; + documents.forEach((document, idx) => { + expect(document).toMatchObject({ + title: mockSearchDocIndex.docs[idx].title, + location: `/docs/default/Component/${entity.metadata.name}/${mockSearchDocIndex.docs[idx].location}`, + text: mockSearchDocIndex.docs[idx].text, + namespace: 'default', + entityTitle: entity!.metadata.title, + componentType: entity!.spec!.type, + lifecycle: entity!.spec!.lifecycle, + owner: '', + kind: entity.kind, + name: entity.metadata.name, + }); + }); }); }); - it('maps a returned entity with a custom locationTemplate', async () => { - const mockConfig = new ConfigReader({ - techdocs: { - legacyUseCaseSensitiveTripletPaths: true, - }, - }); - // Provide an alternate location template. - collator = DefaultTechDocsCollator.fromConfig(mockConfig, { - discovery: mockDiscoveryApi, - tokenManager: mockTokenManager, - locationTemplate: '/software/:name', - logger, + describe('DefaultTechDocsCollator', () => { + let mockDiscoveryApi: jest.Mocked; + let mockTokenManager: jest.Mocked; + let collator: DefaultTechDocsCollator; + + beforeEach(() => { + mockDiscoveryApi = { + getBaseUrl: jest.fn().mockResolvedValue('http://test-backend'), + getExternalBaseUrl: jest.fn(), + }; + mockTokenManager = { + getToken: jest.fn().mockResolvedValue({ token: '' }), + authenticate: jest.fn(), + }; + collator = DefaultTechDocsCollator.fromConfig(new ConfigReader({}), { + discovery: mockDiscoveryApi, + tokenManager: mockTokenManager, + logger, + }); + + worker.use( + rest.get( + 'http://test-backend/static/docs/default/component/test-entity-with-docs/search/search_index.json', + (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), + ), + rest.get('http://test-backend/entities', (_, res, ctx) => + res(ctx.status(200), ctx.json(expectedEntities)), + ), + ); }); - const documents = await collator.execute(); - expect(documents[0]).toMatchObject({ - location: '/software/test-entity-with-docs', + it('should create documents for each tech docs search index', async () => { + const documents = await collator.execute(); + const entity = expectedEntities[0]; + documents.forEach((document, idx) => { + expect(document).toMatchObject({ + title: mockSearchDocIndex.docs[idx].title, + location: `/docs/default/component/${entity.metadata.name}/${mockSearchDocIndex.docs[idx].location}`, + text: mockSearchDocIndex.docs[idx].text, + namespace: 'default', + entityTitle: entity!.metadata.title, + componentType: entity!.spec!.type, + lifecycle: entity!.spec!.lifecycle, + owner: '', + kind: entity.kind.toLocaleLowerCase('en-US'), + name: entity.metadata.name.toLocaleLowerCase('en-US'), + authorization: { + resourceRef: `component:default/${entity.metadata.name}`, + }, + }); + }); + }); + + it('maps a returned entity with a custom locationTemplate', async () => { + const mockConfig = new ConfigReader({ + techdocs: { + legacyUseCaseSensitiveTripletPaths: true, + }, + }); + // Provide an alternate location template. + collator = DefaultTechDocsCollator.fromConfig(mockConfig, { + discovery: mockDiscoveryApi, + tokenManager: mockTokenManager, + locationTemplate: '/software/:name', + logger, + }); + + const documents = await collator.execute(); + expect(documents[0]).toMatchObject({ + location: '/software/test-entity-with-docs', + }); }); }); }); diff --git a/yarn.lock b/yarn.lock index f748204ca3..aeac084923 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4196,6 +4196,18 @@ outvariant "^1.2.1" strict-event-emitter "^0.2.0" +"@mswjs/interceptors@^0.16.3": + version "0.16.4" + resolved "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.16.4.tgz#fa41de240dd094e6ad19e3a6829651589551d159" + integrity sha512-McPKUFlZNS/wo+OAor15k0fv2skK+EdWl9CEcdxAqsN4vKajlxCxDU4B5W/pn1y0TJPSAOmxR6LYFe/8esePrg== + dependencies: + "@open-draft/until" "^1.0.3" + "@xmldom/xmldom" "^0.7.5" + debug "^4.3.3" + headers-polyfill "^3.0.4" + outvariant "^1.2.1" + strict-event-emitter "^0.2.4" + "@n1ru4l/graphql-live-query@^0.9.0": version "0.9.0" resolved "https://registry.npmjs.org/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" @@ -18159,13 +18171,13 @@ msw@^0.39.2: type-fest "^1.2.2" yargs "^17.3.1" -msw@^0.41.0: - version "0.41.1" - resolved "https://registry.npmjs.org/msw/-/msw-0.41.1.tgz#215f835d5c2b1f4a8aca2e92fa7608b0086b6891" - integrity sha512-BNz8u1ORjyAXGaFEJ8mDhJr3nVaACSP4WR7V5XU8I2BnkTuAx93+gR13ovtH1gT66TO8rntOSSfRKZkWpSVufg== +msw@^0.42.0: + version "0.42.0" + resolved "https://registry.npmjs.org/msw/-/msw-0.42.0.tgz#2286aefad82808888914e2bc5e40666e82b2824b" + integrity sha512-vB9rzgiGHoQGfkKpp3QZHxobzfuuQOJk+0bff0wtbK8k3P3CaUSt8bCwvExours682AY4mUfTjIkCsxy0JoS3w== dependencies: "@mswjs/cookies" "^0.2.0" - "@mswjs/interceptors" "^0.15.1" + "@mswjs/interceptors" "^0.16.3" "@open-draft/until" "^1.0.3" "@types/cookie" "^0.4.1" "@types/js-levenshtein" "^1.1.1" @@ -18178,6 +18190,7 @@ msw@^0.41.0: is-node-process "^1.0.1" js-levenshtein "^1.1.6" node-fetch "^2.6.7" + outvariant "^1.3.0" path-to-regexp "^6.2.0" statuses "^2.0.0" strict-event-emitter "^0.2.0" @@ -19086,7 +19099,7 @@ outdent@^0.5.0: resolved "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz#9e10982fdc41492bb473ad13840d22f9655be2ff" integrity sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q== -outvariant@^1.2.1: +outvariant@^1.2.1, outvariant@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz#c39723b1d2cba729c930b74bf962317a81b9b1c9" integrity sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ== @@ -23176,6 +23189,13 @@ strict-event-emitter@^0.2.0: dependencies: events "^3.3.0" +strict-event-emitter@^0.2.4: + version "0.2.4" + resolved "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.4.tgz#365714f0c95f059db31064ca745d5b33e5b30f6e" + integrity sha512-xIqTLS5azUH1djSUsLH9DbP6UnM/nI18vu8d43JigCQEoVsnY+mrlE+qv6kYqs6/1OkMnMIiL6ffedQSZStuoQ== + dependencies: + events "^3.3.0" + strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"