Add a functional 'mockServices.events()'

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2025-04-16 22:24:13 +02:00
parent f6bea04286
commit b3832d10c5
5 changed files with 131 additions and 12 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-test-utils': minor
---
Add a functional `mockServices.events()`
+9 -6
View File
@@ -222,14 +222,17 @@ export namespace mockServices {
partialImpl?: Partial<DiscoveryService> | undefined,
) => ServiceMock<DiscoveryService>;
}
export function events(): EventsService;
// (undocumented)
export namespace events {
const // (undocumented)
factory: () => ServiceFactory<EventsService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<EventsService> | undefined,
) => ServiceMock<EventsService>;
const factory: () => ServiceFactory<
EventsService,
'plugin',
'singleton' | 'multiton'
>;
const mock: (
partialImpl?: Partial<EventsService> | undefined,
) => ServiceMock<EventsService>;
}
export function httpAuth(options?: {
pluginId?: string;
@@ -0,0 +1,56 @@
/*
* Copyright 2025 The Backstage Authors
*
* 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 { MockEventsService } from './MockEventsService';
describe('MockEventsService', () => {
it('notifies subscribers', async () => {
const service = new MockEventsService();
const listener1 = jest.fn();
const listener2 = jest.fn();
await service.subscribe({
id: 'a',
topics: ['topic1'],
onEvent: listener1,
});
await service.subscribe({
id: 'b',
topics: ['topic1', 'topic2'],
onEvent: listener2,
});
expect(listener1).not.toHaveBeenCalled();
expect(listener2).not.toHaveBeenCalled();
await service.publish({
topic: 'topic1',
eventPayload: { payload: 1 },
});
expect(listener1).toHaveBeenCalledTimes(1);
expect(listener2).toHaveBeenCalledTimes(1);
await service.publish({
topic: 'topic2',
eventPayload: { payload: 1 },
});
expect(listener1).toHaveBeenCalledTimes(1);
expect(listener2).toHaveBeenCalledTimes(2);
});
});
@@ -0,0 +1,41 @@
/*
* Copyright 2025 The Backstage Authors
*
* 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 {
EventParams,
EventsService,
EventsServiceSubscribeOptions,
} from '@backstage/plugin-events-node';
export class MockEventsService implements EventsService {
#subscribers: EventsServiceSubscribeOptions[];
constructor() {
this.#subscribers = [];
}
async publish(params: EventParams): Promise<void> {
for (const subscriber of this.#subscribers) {
if (subscriber.topics.includes(params.topic)) {
await subscriber.onEvent(params);
}
}
}
async subscribe(options: EventsServiceSubscribeOptions): Promise<void> {
this.#subscribers.push(options);
}
}
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { auditorServiceFactory } from '@backstage/backend-defaults/auditor';
import { cacheServiceFactory } from '@backstage/backend-defaults/cache';
import { databaseServiceFactory } from '@backstage/backend-defaults/database';
import { HostDiscovery } from '@backstage/backend-defaults/discovery';
@@ -43,10 +44,7 @@ import {
createServiceFactory,
} from '@backstage/backend-plugin-api';
import { ConfigReader } from '@backstage/config';
import {
eventsServiceFactory,
eventsServiceRef,
} from '@backstage/plugin-events-node';
import { EventsService, eventsServiceRef } from '@backstage/plugin-events-node';
import { JsonObject } from '@backstage/types';
import { Knex } from 'knex';
import { MockAuthService } from './MockAuthService';
@@ -54,7 +52,7 @@ import { MockHttpAuthService } from './MockHttpAuthService';
import { MockRootLoggerService } from './MockRootLoggerService';
import { MockUserInfoService } from './MockUserInfoService';
import { mockCredentials } from './mockCredentials';
import { auditorServiceFactory } from '@backstage/backend-defaults/auditor';
import { MockEventsService } from './MockEventsService';
/** @internal */
function createLoggerMock() {
@@ -521,8 +519,24 @@ export namespace mockServices {
}));
}
/**
* Creates a functional mock implementation of the
* {@link @backstage/backend-events-node#eventsServiceRef}.
*/
export function events(): EventsService {
return new MockEventsService();
}
export namespace events {
export const factory = () => eventsServiceFactory;
/**
* Creates a functional mock factory for the
* {@link @backstage/backend-events-node#eventsServiceRef}.
*/
export const factory = simpleFactoryWithOptions(eventsServiceRef, events);
/**
* Creates a mock of the
* {@link @backstage/backend-events-node#eventsServiceRef}, optionally
* with some given method implementations.
*/
export const mock = simpleMock(eventsServiceRef, () => ({
publish: jest.fn(),
subscribe: jest.fn(),