[PM-6426] Adding jest tests to the ForegroundTaskSchedulerService and the BackgroundTaskSchedulerService

This commit is contained in:
Cesar Gonzalez 2024-06-07 06:40:55 -05:00
parent fae0f65ab2
commit 2f769eb4d7
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
3 changed files with 211 additions and 6 deletions

View File

@ -0,0 +1,127 @@
import { mock, MockProxy } from "jest-mock-extended";
import { Observable } from "rxjs";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { ScheduledTaskNames } from "@bitwarden/common/platform/enums/scheduled-task-name.enum";
import { GlobalState, StateProvider } from "@bitwarden/common/platform/state";
import { createPortSpyMock } from "../../../autofill/spec/autofill-mocks";
import {
flushPromises,
sendPortMessage,
triggerPortOnDisconnectEvent,
triggerRuntimeOnConnectEvent,
} from "../../../autofill/spec/testing-utils";
import {
BrowserTaskSchedulerPortActions,
BrowserTaskSchedulerPortName,
} from "../abstractions/browser-task-scheduler.service";
import { BackgroundTaskSchedulerService } from "./background-task-scheduler.service";
describe("BackgroundTaskSchedulerService", () => {
let logService: MockProxy<LogService>;
let stateProvider: MockProxy<StateProvider>;
let globalStateMock: MockProxy<GlobalState<any>>;
let portMock: chrome.runtime.Port;
let backgroundTaskSchedulerService: BackgroundTaskSchedulerService;
beforeEach(() => {
logService = mock<LogService>();
globalStateMock = mock<GlobalState<any>>({
state$: mock<Observable<any>>(),
update: jest.fn((callback) => callback([], {} as any)),
});
stateProvider = mock<StateProvider>({
getGlobal: jest.fn(() => globalStateMock),
});
portMock = createPortSpyMock(BrowserTaskSchedulerPortName);
backgroundTaskSchedulerService = new BackgroundTaskSchedulerService(logService, stateProvider);
jest.spyOn(globalThis, "setTimeout");
});
afterEach(() => {
jest.clearAllMocks();
});
describe("ports on connect", () => {
it("ignores port connections that do not have the correct task scheduler port name", () => {
const portMockWithDifferentName = createPortSpyMock("different-name");
triggerRuntimeOnConnectEvent(portMockWithDifferentName);
expect(portMockWithDifferentName.onMessage.addListener).not.toHaveBeenCalled();
expect(portMockWithDifferentName.onDisconnect.addListener).not.toHaveBeenCalled();
});
it("sets up onMessage and onDisconnect listeners for connected ports", () => {
triggerRuntimeOnConnectEvent(portMock);
expect(portMock.onMessage.addListener).toHaveBeenCalled();
expect(portMock.onDisconnect.addListener).toHaveBeenCalled();
});
});
describe("ports on disconnect", () => {
it("removes the port from the set of connected ports", () => {
triggerRuntimeOnConnectEvent(portMock);
expect(backgroundTaskSchedulerService["ports"].size).toBe(1);
triggerPortOnDisconnectEvent(portMock);
expect(backgroundTaskSchedulerService["ports"].size).toBe(0);
});
});
describe("port message handlers", () => {
beforeEach(() => {
triggerRuntimeOnConnectEvent(portMock);
backgroundTaskSchedulerService.registerTaskHandler(
ScheduledTaskNames.loginStrategySessionTimeout,
jest.fn(),
);
});
it("sets a setTimeout backup alarm", async () => {
sendPortMessage(portMock, {
action: BrowserTaskSchedulerPortActions.setTimeout,
taskName: ScheduledTaskNames.loginStrategySessionTimeout,
delayInMs: 1000,
});
await flushPromises();
expect(globalThis.setTimeout).toHaveBeenCalled();
expect(chrome.alarms.create).toHaveBeenCalledWith(
ScheduledTaskNames.loginStrategySessionTimeout,
{ delayInMinutes: 0.5 },
expect.any(Function),
);
});
it("sets a setInterval backup alarm", async () => {
sendPortMessage(portMock, {
action: BrowserTaskSchedulerPortActions.setInterval,
taskName: ScheduledTaskNames.loginStrategySessionTimeout,
intervalInMs: 600000,
});
await flushPromises();
expect(chrome.alarms.create).toHaveBeenCalledWith(
ScheduledTaskNames.loginStrategySessionTimeout,
{ delayInMinutes: 10, periodInMinutes: 10 },
expect.any(Function),
);
});
it("clears a scheduled alarm", async () => {
sendPortMessage(portMock, {
action: BrowserTaskSchedulerPortActions.clearAlarm,
alarmName: ScheduledTaskNames.loginStrategySessionTimeout,
});
await flushPromises();
expect(chrome.alarms.clear).toHaveBeenCalledWith(
ScheduledTaskNames.loginStrategySessionTimeout,
expect.any(Function),
);
});
});
});

View File

@ -25,6 +25,10 @@ export class BackgroundTaskSchedulerService extends BrowserTaskSchedulerServiceI
* @param port - The port that was connected. * @param port - The port that was connected.
*/ */
private handlePortOnConnect = (port: chrome.runtime.Port) => { private handlePortOnConnect = (port: chrome.runtime.Port) => {
if (port.name !== BrowserTaskSchedulerPortName) {
return;
}
this.ports.add(port); this.ports.add(port);
port.onMessage.addListener(this.handlePortMessage); port.onMessage.addListener(this.handlePortMessage);
port.onDisconnect.addListener(this.handlePortOnDisconnect); port.onDisconnect.addListener(this.handlePortOnDisconnect);
@ -50,10 +54,6 @@ export class BackgroundTaskSchedulerService extends BrowserTaskSchedulerServiceI
message: BrowserTaskSchedulerPortMessage, message: BrowserTaskSchedulerPortMessage,
port: chrome.runtime.Port, port: chrome.runtime.Port,
) => { ) => {
if (port.name !== BrowserTaskSchedulerPortName) {
return;
}
if (message.action === BrowserTaskSchedulerPortActions.setTimeout) { if (message.action === BrowserTaskSchedulerPortActions.setTimeout) {
super.setTimeout(message.taskName, message.delayInMs); super.setTimeout(message.taskName, message.delayInMs);
return; return;
@ -65,8 +65,7 @@ export class BackgroundTaskSchedulerService extends BrowserTaskSchedulerServiceI
} }
if (message.action === BrowserTaskSchedulerPortActions.clearAlarm) { if (message.action === BrowserTaskSchedulerPortActions.clearAlarm) {
void super.clearScheduledAlarm(message.alarmName); super.clearScheduledAlarm(message.alarmName).catch((error) => this.logService.error(error));
return;
} }
}; };
} }

View File

@ -0,0 +1,79 @@
import { mock, MockProxy } from "jest-mock-extended";
import { Observable } from "rxjs";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { ScheduledTaskNames } from "@bitwarden/common/platform/enums/scheduled-task-name.enum";
import { GlobalState, StateProvider } from "@bitwarden/common/platform/state";
import { createPortSpyMock } from "../../../autofill/spec/autofill-mocks";
import { flushPromises } from "../../../autofill/spec/testing-utils";
import {
BrowserTaskSchedulerPortActions,
BrowserTaskSchedulerPortName,
} from "../abstractions/browser-task-scheduler.service";
import { ForegroundTaskSchedulerService } from "./foreground-task-scheduler.service";
describe("ForegroundTaskSchedulerService", () => {
let logService: MockProxy<LogService>;
let stateProvider: MockProxy<StateProvider>;
let globalStateMock: MockProxy<GlobalState<any>>;
let portMock: chrome.runtime.Port;
let foregroundTaskSchedulerService: ForegroundTaskSchedulerService;
beforeEach(() => {
logService = mock<LogService>();
globalStateMock = mock<GlobalState<any>>({
state$: mock<Observable<any>>(),
update: jest.fn((callback) => callback([], {} as any)),
});
stateProvider = mock<StateProvider>({
getGlobal: jest.fn(() => globalStateMock),
});
portMock = createPortSpyMock(BrowserTaskSchedulerPortName);
foregroundTaskSchedulerService = new ForegroundTaskSchedulerService(logService, stateProvider);
foregroundTaskSchedulerService["port"] = portMock;
foregroundTaskSchedulerService.registerTaskHandler(
ScheduledTaskNames.loginStrategySessionTimeout,
jest.fn(),
);
jest.spyOn(globalThis, "setTimeout");
jest.spyOn(globalThis, "setInterval");
});
afterEach(() => {
jest.clearAllMocks();
});
it("sets a timeout for a task and sends a message to the background to set up a backup timeout alarm", async () => {
foregroundTaskSchedulerService.setTimeout(ScheduledTaskNames.loginStrategySessionTimeout, 1000);
await flushPromises();
expect(globalThis.setTimeout).toHaveBeenCalledWith(expect.any(Function), 1000);
expect(chrome.alarms.create).toHaveBeenCalledWith(
"loginStrategySessionTimeout",
{ delayInMinutes: 0.5 },
expect.any(Function),
);
expect(portMock.postMessage).toHaveBeenCalledWith({
action: BrowserTaskSchedulerPortActions.setTimeout,
taskName: ScheduledTaskNames.loginStrategySessionTimeout,
delayInMs: 1000,
});
});
it("sets an interval for a task and sends a message to the background to set up a backup interval alarm", async () => {
foregroundTaskSchedulerService.setInterval(
ScheduledTaskNames.loginStrategySessionTimeout,
1000,
);
await flushPromises();
expect(globalThis.setInterval).toHaveBeenCalledWith(expect.any(Function), 1000);
expect(portMock.postMessage).toHaveBeenCalledWith({
action: BrowserTaskSchedulerPortActions.setInterval,
taskName: ScheduledTaskNames.loginStrategySessionTimeout,
intervalInMs: 1000,
});
});
});