mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-11 00:31:45 +01:00
[PM-5189] Implementing jest tests for the OverlayBackground
This commit is contained in:
parent
f3c0a24a1d
commit
b9d257046c
@ -1,14 +1,15 @@
|
||||
import { mock, MockProxy, mockReset } from "jest-mock-extended";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants";
|
||||
import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import { AutofillSettingsServiceAbstraction as AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
import {
|
||||
DefaultDomainSettingsService,
|
||||
DomainSettingsService,
|
||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||
import {
|
||||
EnvironmentService,
|
||||
Region,
|
||||
@ -27,60 +28,74 @@ import {
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
import { DefaultBrowserStateService } from "../../platform/services/default-browser-state.service";
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
import { BrowserPlatformUtilsService } from "../../platform/services/platform-utils/browser-platform-utils.service";
|
||||
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||
import { createChromeTabMock, createAutofillPageDetailsMock } from "../spec/autofill-mocks";
|
||||
import { sendMockExtensionMessage } from "../spec/testing-utils";
|
||||
import { flushPromises, sendMockExtensionMessage } from "../spec/testing-utils";
|
||||
|
||||
import {
|
||||
PageDetailsForTab,
|
||||
SubFrameOffsetData,
|
||||
SubFrameOffsetsForTab,
|
||||
} from "./abstractions/overlay.background";
|
||||
import { OverlayBackground } from "./overlay.background";
|
||||
|
||||
describe("OverlayBackground", () => {
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
let accountService: FakeAccountService;
|
||||
let fakeStateProvider: FakeStateProvider;
|
||||
let showFaviconsMock$: BehaviorSubject<boolean>;
|
||||
let domainSettingsService: DomainSettingsService;
|
||||
let logService: MockProxy<LogService>;
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let autofillService: MockProxy<AutofillService>;
|
||||
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
||||
let authService: MockProxy<AuthService>;
|
||||
let environmentMock$: BehaviorSubject<CloudEnvironment>;
|
||||
let environmentService: MockProxy<EnvironmentService>;
|
||||
let stateService: MockProxy<DefaultBrowserStateService>;
|
||||
let inlineMenuVisibilityMock$: BehaviorSubject<InlineMenuVisibilitySetting>;
|
||||
let autofillSettingsService: MockProxy<AutofillSettingsService>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let platformUtilsService: MockProxy<BrowserPlatformUtilsService>;
|
||||
let selectedThemeMock$: BehaviorSubject<ThemeType>;
|
||||
let themeStateService: MockProxy<ThemeStateService>;
|
||||
let overlayBackground: OverlayBackground;
|
||||
let portKeyForTabSpy: Record<number, string>;
|
||||
let pageDetailsForTabSpy: PageDetailsForTab;
|
||||
let subFrameOffsetsSpy: SubFrameOffsetsForTab;
|
||||
let getFrameDetailsSpy: jest.SpyInstance;
|
||||
let tabsSendMessageSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
fakeStateProvider = new FakeStateProvider(accountService);
|
||||
showFaviconsMock$ = new BehaviorSubject(true);
|
||||
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
|
||||
domainSettingsService.showFavicons$ = of(true);
|
||||
domainSettingsService.showFavicons$ = showFaviconsMock$;
|
||||
logService = mock<LogService>();
|
||||
cipherService = mock<CipherService>();
|
||||
autofillService = mock<AutofillService>();
|
||||
authService = mock<AuthService>({
|
||||
activeAccountStatus$: new BehaviorSubject(AuthenticationStatus.Unlocked),
|
||||
});
|
||||
environmentService = mock<EnvironmentService>({
|
||||
environment$: new BehaviorSubject(
|
||||
new CloudEnvironment({
|
||||
key: Region.US,
|
||||
domain: "bitwarden.com",
|
||||
urls: { icons: "https://icons.bitwarden.com/" },
|
||||
}),
|
||||
),
|
||||
});
|
||||
stateService = mock<DefaultBrowserStateService>();
|
||||
autofillSettingsService = mock<AutofillSettingsService>({
|
||||
inlineMenuVisibility$: of(AutofillOverlayVisibility.OnFieldFocus),
|
||||
});
|
||||
activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
|
||||
authService = mock<AuthService>();
|
||||
authService.activeAccountStatus$ = activeAccountStatusMock$;
|
||||
environmentMock$ = new BehaviorSubject(
|
||||
new CloudEnvironment({
|
||||
key: Region.US,
|
||||
domain: "bitwarden.com",
|
||||
urls: { icons: "https://icons.bitwarden.com/" },
|
||||
}),
|
||||
);
|
||||
environmentService = mock<EnvironmentService>();
|
||||
environmentService.environment$ = environmentMock$;
|
||||
inlineMenuVisibilityMock$ = new BehaviorSubject(AutofillOverlayVisibility.OnFieldFocus);
|
||||
autofillSettingsService = mock<AutofillSettingsService>();
|
||||
autofillSettingsService.inlineMenuVisibility$ = inlineMenuVisibilityMock$;
|
||||
i18nService = mock<I18nService>();
|
||||
platformUtilsService = mock<BrowserPlatformUtilsService>();
|
||||
themeStateService = mock<ThemeStateService>({
|
||||
selectedTheme$: of(ThemeType.Light),
|
||||
});
|
||||
selectedThemeMock$ = new BehaviorSubject(ThemeType.Light);
|
||||
themeStateService = mock<ThemeStateService>();
|
||||
themeStateService.selectedTheme$ = selectedThemeMock$;
|
||||
overlayBackground = new OverlayBackground(
|
||||
logService,
|
||||
cipherService,
|
||||
@ -88,12 +103,16 @@ describe("OverlayBackground", () => {
|
||||
authService,
|
||||
environmentService,
|
||||
domainSettingsService,
|
||||
stateService,
|
||||
autofillSettingsService,
|
||||
i18nService,
|
||||
platformUtilsService,
|
||||
themeStateService,
|
||||
);
|
||||
portKeyForTabSpy = overlayBackground["portKeyForTab"];
|
||||
pageDetailsForTabSpy = overlayBackground["pageDetailsForTab"];
|
||||
subFrameOffsetsSpy = overlayBackground["subFrameOffsetsForTab"];
|
||||
getFrameDetailsSpy = jest.spyOn(BrowserApi, "getFrameDetails");
|
||||
tabsSendMessageSpy = jest.spyOn(BrowserApi, "tabSendMessage");
|
||||
|
||||
void overlayBackground.init();
|
||||
});
|
||||
@ -103,21 +122,119 @@ describe("OverlayBackground", () => {
|
||||
mockReset(cipherService);
|
||||
});
|
||||
|
||||
// TODO: describe init
|
||||
|
||||
describe("removePageDetails", () => {
|
||||
it("removes the page details for a specific tab from the pageDetailsForTab object", () => {
|
||||
const tabId = 1;
|
||||
const frameId = 2;
|
||||
describe("storing pageDetails", () => {
|
||||
const tabId = 1;
|
||||
|
||||
beforeEach(() => {
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({ tab: createChromeTabMock({ id: tabId }), frameId }),
|
||||
mock<chrome.runtime.MessageSender>({ tab: createChromeTabMock({ id: tabId }), frameId: 0 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("generates a random 12 character string used to validate port messages from the tab", () => {
|
||||
expect(portKeyForTabSpy[tabId]).toHaveLength(12);
|
||||
});
|
||||
|
||||
it("stores the page details for the tab", () => {
|
||||
expect(pageDetailsForTabSpy[tabId]).toBeDefined();
|
||||
});
|
||||
|
||||
describe("building sub frame offsets", () => {
|
||||
let getFrameCounter: number = 2;
|
||||
|
||||
beforeEach(() => {
|
||||
getFrameDetailsSpy.mockImplementation((_details: chrome.webNavigation.GetFrameDetails) => {
|
||||
getFrameCounter--;
|
||||
return mock<chrome.webNavigation.GetFrameResultDetails>({
|
||||
parentFrameId: getFrameCounter,
|
||||
});
|
||||
});
|
||||
tabsSendMessageSpy.mockResolvedValue(mock<SubFrameOffsetData>());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getFrameCounter = 2;
|
||||
});
|
||||
|
||||
it("builds the offset values for a sub frame within the tab", () => {
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({
|
||||
tab: createChromeTabMock({ id: tabId }),
|
||||
frameId: 1,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(subFrameOffsetsSpy[tabId]).toBeDefined();
|
||||
expect(pageDetailsForTabSpy[tabId].size).toBe(2);
|
||||
});
|
||||
|
||||
it("skips building offset values for a previously calculated sub frame", async () => {
|
||||
getFrameCounter = 0;
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({
|
||||
tab: createChromeTabMock({ id: tabId }),
|
||||
frameId: 1,
|
||||
}),
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({
|
||||
tab: createChromeTabMock({ id: tabId }),
|
||||
frameId: 1,
|
||||
}),
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
expect(getFrameDetailsSpy).toHaveBeenCalledTimes(1);
|
||||
expect(subFrameOffsetsSpy[tabId]).toStrictEqual(
|
||||
new Map([[1, { left: 0, top: 0, url: "url" }]]),
|
||||
);
|
||||
});
|
||||
|
||||
it("will attempt to build the sub frame offsets by posting window messages if a set of offsets is not returned", async () => {
|
||||
const tab = createChromeTabMock({ id: tabId });
|
||||
const frameId = 1;
|
||||
tabsSendMessageSpy.mockResolvedValueOnce(null);
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({
|
||||
tab,
|
||||
frameId,
|
||||
}),
|
||||
);
|
||||
await flushPromises();
|
||||
|
||||
expect(tabsSendMessageSpy).toHaveBeenCalledWith(
|
||||
tab,
|
||||
{
|
||||
command: "getSubFrameOffsetsFromWindowMessage",
|
||||
subFrameId: frameId,
|
||||
},
|
||||
{ frameId },
|
||||
);
|
||||
expect(subFrameOffsetsSpy[tabId]).toStrictEqual(new Map([[frameId, null]]));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("removing pageDetails", () => {
|
||||
it("removes the page details, sub frame details, and port key for a specific tab from the pageDetailsForTab object", () => {
|
||||
const tabId = 1;
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: createAutofillPageDetailsMock() },
|
||||
mock<chrome.runtime.MessageSender>({ tab: createChromeTabMock({ id: tabId }), frameId: 1 }),
|
||||
);
|
||||
|
||||
overlayBackground.removePageDetails(tabId);
|
||||
|
||||
expect(overlayBackground["pageDetailsForTab"][tabId]).toBeUndefined();
|
||||
expect(pageDetailsForTabSpy[tabId]).toBeUndefined();
|
||||
expect(subFrameOffsetsSpy[tabId]).toBeUndefined();
|
||||
expect(portKeyForTabSpy[tabId]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@ -128,7 +127,6 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
private authService: AuthService,
|
||||
private environmentService: EnvironmentService,
|
||||
private domainSettingsService: DomainSettingsService,
|
||||
private stateService: StateService,
|
||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
@ -261,6 +259,13 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
pageDetailsMap.set(sender.frameId, pageDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sub frame offset calculations for the given tab and frame id.
|
||||
* Is used in setting the position of the inline menu list and button.
|
||||
*
|
||||
* @param message - The message received from the `updateSubFrameData` command
|
||||
* @param sender - The sender of the message
|
||||
*/
|
||||
private updateSubFrameData(
|
||||
message: OverlayBackgroundExtensionMessage,
|
||||
sender: chrome.runtime.MessageSender,
|
||||
|
@ -1049,7 +1049,6 @@ export default class MainBackground {
|
||||
this.authService,
|
||||
this.environmentService,
|
||||
this.domainSettingsService,
|
||||
this.stateService,
|
||||
this.autofillSettingsService,
|
||||
this.i18nService,
|
||||
this.platformUtilsService,
|
||||
|
Loading…
Reference in New Issue
Block a user