Skip to content
This repository has been archived by the owner on Dec 27, 2024. It is now read-only.

Commit

Permalink
test: unit test announcements-backend (#87)
Browse files Browse the repository at this point in the history
* test: unit test backend

Signed-off-by: Kurt King <[email protected]>

* chore: uncomment expect statement

Signed-off-by: Kurt King <[email protected]>

* chore: move dep to dev-deps

Signed-off-by: Kurt King <[email protected]>

* chore: include changeset

Signed-off-by: Kurt King <[email protected]>

---------

Signed-off-by: Kurt King <[email protected]>
  • Loading branch information
kurtaking authored Oct 27, 2023
1 parent c81ae81 commit bce49e0
Show file tree
Hide file tree
Showing 10 changed files with 901 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-fans-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@procore-oss/backstage-plugin-announcements-backend': patch
---

Improves test coverage significantly for the backend plugin
3 changes: 3 additions & 0 deletions plugins/announcements-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@backstage/plugin-auth-node": "^0.4.0",
"@backstage/plugin-permission-common": "^0.7.9",
"@backstage/plugin-permission-node": "^0.7.17",
"@backstage/plugin-search-backend-node": "^1.2.10",
"@backstage/plugin-search-common": "^1.2.7",
"@procore-oss/backstage-plugin-announcements-common": "^0.1.2",
"@types/express": "^4.17.6",
Expand All @@ -52,7 +53,9 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.2.7",
"@backstage/cli": "^0.23.1",
"@backstage/test-utils": "^1.4.4",
"@types/supertest": "^2.0.15",
"@types/uuid": "^8.3.4",
"better-sqlite3": "^8.7.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { AnnouncementCollatorFactory } from './AnnouncementCollatorFactory';
import { Readable } from 'stream';
import { getVoidLogger } from '@backstage/backend-common';
import { TestPipeline } from '@backstage/plugin-search-backend-node';
import { setupRequestMockHandlers } from '@backstage/test-utils';
import { setupServer } from 'msw/node';
import { rest } from 'msw';

const mockAnnouncements = {
count: 3,
results: [
{
id: '1',
title: 'title',
publisher: 'publisher1',
body: 'body',
excerpt: 'excerpt',
created_at: 'created_at',
},
{
id: '2',
title: 'title',
publisher: 'publisher2',
body: 'body',
excerpt: 'excerpt',
created_at: 'created_at',
},
{
id: '3',
title: 'title',
publisher: 'publisher3',
body: 'body',
excerpt: 'excerpt',
created_at: 'created_at',
},
],
};

describe('AnnouncementCollatorFactory', () => {
const logger = getVoidLogger();
const mockDiscoveryApi = {
getBaseUrl: jest.fn().mockReturnValue('http://localhost:7007/api'),
};

const factory = AnnouncementCollatorFactory.fromConfig({
logger,
discoveryApi: mockDiscoveryApi,
});

it('has expected type', () => {
expect(factory.type).toBe('announcements');
});

describe('getCollator', () => {
const worker = setupServer();
setupRequestMockHandlers(worker);

let collator: Readable;
beforeEach(async () => {
collator = await factory.getCollator();
worker.use(
rest.get('http://localhost:7007/api/announcements', (_, res, ctx) =>
res(ctx.status(200), ctx.json(mockAnnouncements)),
),
);
});

it('should return a Readable stream', async () => {
collator = await factory.getCollator();
expect(collator).toBeInstanceOf(Readable);
});

it('runs against announcements', async () => {
collator = await factory.getCollator();
const pipeline = TestPipeline.fromCollator(collator);
const { documents } = await pipeline.execute();
expect(mockDiscoveryApi.getBaseUrl).toHaveBeenCalledWith('announcements');
expect(documents).toHaveLength(mockAnnouncements.results.length);
});
});
});
68 changes: 68 additions & 0 deletions plugins/announcements-backend/src/search/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { setupRequestMockHandlers } from '@backstage/test-utils';
import { AnnouncementsClient } from './api';
import { rest } from 'msw';
import { setupServer } from 'msw/node';

describe('AnnouncementsClient', () => {
const server = setupServer();
const mockBaseUrl = 'http://localhost:7007/api/';
const discoveryApi = { getBaseUrl: async () => mockBaseUrl };

setupRequestMockHandlers(server);

let client: AnnouncementsClient;
beforeEach(() => {
client = new AnnouncementsClient({ discoveryApi });
server.listen();
});

afterEach(() => server.resetHandlers());
afterAll(() => server.close());

it('handles no announcements', async () => {
server.use(
rest.get(`${mockBaseUrl}/announcements`, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ count: 0, results: [] })),
),
);
expect(await client.announcements()).toEqual([]);
});

it('returns announcements', async () => {
const announcements = [
{
id: '1',
title: 'announcement1',
excerpt: 'excerpt',
body: 'body',
publisher: 'publisher',
created_at: '2021-01-01T00:00:00Z',
},
{
id: '1',
title: 'announcement2',
excerpt: 'excerpt',
body: 'body',
publisher: 'publisher2',
created_at: '2021-01-02T00:00:00Z',
},
];
server.use(
rest.get(`${mockBaseUrl}/announcements`, (_, res, ctx) =>
res(ctx.status(200), ctx.json({ count: 2, results: announcements })),
),
);
expect(await client.announcements()).toEqual(announcements);
});

it('throws on error', async () => {
server.use(
rest.get(`${mockBaseUrl}/announcements`, (_, res, ctx) =>
res(ctx.status(500)),
),
);
await expect(client.announcements()).rejects.toThrow(
'Request failed with 500 Error',
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
import { buildAnnouncementsContext } from './announcementsContextBuilder';
import { getVoidLogger } from '@backstage/backend-common';
import { initializePersistenceContext } from './persistence/persistenceContext';

jest.mock('./persistence/persistenceContext', () => ({
initializePersistenceContext: jest.fn(),
}));

describe('buildAnnouncementsContext', () => {
it('returns context with logger, persistenceContext, and permissions properties', async () => {
const logger = getVoidLogger();
const database = {
getClient: jest.fn(),
url: 'url',
};
const permissions: PermissionEvaluator = {
authorize: jest.fn(),
authorizeConditional: jest.fn(),
};

const context = await buildAnnouncementsContext({
logger,
database,
permissions,
});

expect(context).toStrictEqual({
logger,
persistenceContext: await initializePersistenceContext(database),
permissions,
});
});
});
Loading

0 comments on commit bce49e0

Please sign in to comment.