diff --git a/plugins/catalog-graphql/src/graphql/module.test.ts b/plugins/catalog-graphql/src/graphql/module.test.ts new file mode 100644 index 0000000000..09708f68f4 --- /dev/null +++ b/plugins/catalog-graphql/src/graphql/module.test.ts @@ -0,0 +1,305 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createModule } from './module'; +import { execute } from 'graphql'; +import { rest } from 'msw'; +import { setupServer } from 'msw/node'; +import { ConfigReader } from '@backstage/config'; +import { ReaderEntity } from '../service/client'; +import { createLogger } from 'winston'; +import { gql } from 'apollo-server'; + +describe('Catalog Module', () => { + const worker = setupServer(); + const mockCatalogBaseUrl = 'http://im.mock'; + const mockConfig = ConfigReader.fromConfigs([ + { + context: '', + data: { + backend: { + baseUrl: mockCatalogBaseUrl, + }, + }, + }, + ]); + + beforeAll(() => worker.listen()); + afterAll(() => worker.close()); + + afterEach(() => worker.resetHandlers()); + + describe('Default Entity', () => { + beforeEach(() => { + const mockResponse: ReaderEntity[] = [ + { + apiVersion: 'something', + kind: 'Component', + metadata: { + annotations: {}, + etag: '123', + generation: 1, + labels: {}, + name: 'Ben', + namespace: 'Blames', + uid: '123', + }, + spec: { + type: 'thing', + lifecycle: 'something', + owner: 'auser', + }, + }, + ]; + + worker.use( + rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) => + res(ctx.status(200), ctx.json(mockResponse)), + ), + ); + }); + + it('should call the catalog client when requesting entities', async () => { + const { schema } = await createModule({ + config: mockConfig, + logger: createLogger(), + }); + + const result = await execute({ + schema, + document: gql` + query { + catalog { + list { + kind + apiVersion + metadata { + name + } + } + } + } + `, + }); + + const [catalogItem] = result.data?.catalog.list; + expect(catalogItem.kind).toBe('Component'); + expect(catalogItem.apiVersion).toBe('something'); + expect(catalogItem.metadata.name).toBe('Ben'); + }); + + it('Defaults to empty annotations when none are provided', async () => { + const mockResponse: ReaderEntity[] = [ + { + apiVersion: 'something', + kind: 'Component', + metadata: { + annotations: null as any, + etag: '123', + generation: 1, + labels: {}, + name: 'Ben', + namespace: 'Blames', + uid: '123', + }, + spec: { + type: 'thing', + lifecycle: 'something', + owner: 'auser', + }, + }, + ]; + worker.use( + rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) => + res(ctx.status(200), ctx.json(mockResponse)), + ), + ); + + const { schema } = await createModule({ + config: mockConfig, + logger: createLogger(), + }); + + const result = await execute({ + schema, + document: gql` + query { + catalog { + list { + metadata { + annotations + } + } + } + } + `, + }); + + const [catalogItem] = result.data?.catalog.list; + expect(catalogItem.metadata.annotations).toEqual({}); + }); + + it('Defaults to empty labels when none are provided', async () => { + const mockResponse: ReaderEntity[] = [ + { + apiVersion: 'something', + kind: 'Component', + metadata: { + annotations: {}, + etag: '123', + generation: 1, + labels: null as any, + name: 'Ben', + namespace: 'Blames', + uid: '123', + }, + spec: { + type: 'thing', + lifecycle: 'something', + owner: 'auser', + }, + }, + ]; + worker.use( + rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) => + res(ctx.status(200), ctx.json(mockResponse)), + ), + ); + + const { schema } = await createModule({ + config: mockConfig, + logger: createLogger(), + }); + + const result = await execute({ + schema, + document: gql` + query { + catalog { + list { + metadata { + labels + } + } + } + } + `, + }); + + const [catalogItem] = result.data?.catalog.list; + expect(catalogItem.metadata.labels).toEqual({}); + }); + it('Returns the correct record from the annotation dictionary', async () => { + const mockResponse: ReaderEntity[] = [ + { + apiVersion: 'something', + kind: 'Component', + metadata: { + annotations: { lob: 'bloben' }, + etag: '123', + generation: 1, + labels: {}, + name: 'Ben', + namespace: 'Blames', + uid: '123', + }, + spec: { + type: 'thing', + lifecycle: 'something', + owner: 'auser', + }, + }, + ]; + worker.use( + rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) => + res(ctx.status(200), ctx.json(mockResponse)), + ), + ); + + const { schema } = await createModule({ + config: mockConfig, + logger: createLogger(), + }); + + const result = await execute({ + schema, + document: gql` + query { + catalog { + list { + metadata { + test: annotation(name: "lob") + } + } + } + } + `, + }); + + const [catalogItem] = result.data?.catalog.list; + expect(catalogItem.metadata.test).toEqual('bloben'); + }); + it('Returns the correct record from the labels dictionary', async () => { + const mockResponse: ReaderEntity[] = [ + { + apiVersion: 'something', + kind: 'Component', + metadata: { + annotations: {}, + etag: '123', + generation: 1, + labels: { lob2: 'bloben' }, + name: 'Ben', + namespace: 'Blames', + uid: '123', + }, + spec: { + type: 'thing', + lifecycle: 'something', + owner: 'auser', + }, + }, + ]; + worker.use( + rest.get(`${mockCatalogBaseUrl}/catalog/entities`, (_, res, ctx) => + res(ctx.status(200), ctx.json(mockResponse)), + ), + ); + + const { schema } = await createModule({ + config: mockConfig, + logger: createLogger(), + }); + + const result = await execute({ + schema, + document: gql` + query { + catalog { + list { + metadata { + test: label(name: "lob2") + } + } + } + } + `, + }); + + const [catalogItem] = result.data?.catalog.list; + expect(catalogItem.metadata.test).toEqual('bloben'); + }); + }); +});