mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 07:43:35 +00:00
PM-25448 return null appropriately for subframe rects in order to reposition inline menu (#17129)
This commit is contained in:
@@ -32,6 +32,17 @@ import { InlineMenuFieldQualificationService } from "./inline-menu-field-qualifi
|
||||
|
||||
const defaultWindowReadyState = document.readyState;
|
||||
const defaultDocumentVisibilityState = document.visibilityState;
|
||||
|
||||
const mockRect = (rect: { left: number; top: number; width: number; height: number }) =>
|
||||
({
|
||||
...rect,
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
right: rect.left + rect.width,
|
||||
bottom: rect.top + rect.height,
|
||||
toJSON: () => ({}),
|
||||
}) as DOMRectReadOnly;
|
||||
|
||||
describe("AutofillOverlayContentService", () => {
|
||||
let domQueryService: DomQueryService;
|
||||
let domElementVisibilityService: DomElementVisibilityService;
|
||||
@@ -2154,6 +2165,10 @@ describe("AutofillOverlayContentService", () => {
|
||||
});
|
||||
|
||||
it("calculates the sub frame's offsets if a single frame with the referenced url exists", async () => {
|
||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||
jest
|
||||
.spyOn(iframe, "getBoundingClientRect")
|
||||
.mockReturnValue(mockRect({ left: 0, top: 0, width: 1, height: 1 }));
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
command: "getSubFrameOffsets",
|
||||
@@ -2270,6 +2285,9 @@ describe("AutofillOverlayContentService", () => {
|
||||
});
|
||||
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||
jest
|
||||
.spyOn(iframe, "getBoundingClientRect")
|
||||
.mockReturnValue(mockRect({ width: 1, height: 1, left: 2, top: 2 }));
|
||||
const subFrameData = {
|
||||
url: "https://example.com/",
|
||||
frameId: 10,
|
||||
@@ -2305,6 +2323,9 @@ describe("AutofillOverlayContentService", () => {
|
||||
it("posts the calculated sub frame data to the background", async () => {
|
||||
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||
jest
|
||||
.spyOn(iframe, "getBoundingClientRect")
|
||||
.mockReturnValue(mockRect({ width: 1, height: 1, left: 2, top: 2 }));
|
||||
const subFrameData = {
|
||||
url: "https://example.com/",
|
||||
frameId: 10,
|
||||
@@ -2335,6 +2356,39 @@ describe("AutofillOverlayContentService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("calculateSubFrameOffsets", () => {
|
||||
it("returns null when iframe has zero width and height", () => {
|
||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||
|
||||
jest
|
||||
.spyOn(iframe, "getBoundingClientRect")
|
||||
.mockReturnValue(mockRect({ left: 0, top: 0, width: 0, height: 0 }));
|
||||
|
||||
const result = autofillOverlayContentService["calculateSubFrameOffsets"](
|
||||
iframe,
|
||||
"https://example.com/",
|
||||
10,
|
||||
);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when iframe is not connected to the document", () => {
|
||||
const iframe = document.createElement("iframe") as HTMLIFrameElement;
|
||||
|
||||
jest
|
||||
.spyOn(iframe, "getBoundingClientRect")
|
||||
.mockReturnValue(mockRect({ width: 100, height: 50, left: 10, top: 20 }));
|
||||
|
||||
const result = autofillOverlayContentService["calculateSubFrameOffsets"](
|
||||
iframe,
|
||||
"https://example.com/",
|
||||
10,
|
||||
);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("checkMostRecentlyFocusedFieldHasValue message handler", () => {
|
||||
it("returns true if the most recently focused field has a truthy value", async () => {
|
||||
autofillOverlayContentService["mostRecentlyFocusedField"] = mock<
|
||||
|
||||
@@ -1485,12 +1485,17 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
||||
frameId?: number,
|
||||
): SubFrameOffsetData {
|
||||
const iframeRect = iframeElement.getBoundingClientRect();
|
||||
const iframeRectHasSize = iframeRect.width > 0 && iframeRect.height > 0;
|
||||
const iframeStyles = globalThis.getComputedStyle(iframeElement);
|
||||
const paddingLeft = parseInt(iframeStyles.getPropertyValue("padding-left")) || 0;
|
||||
const paddingTop = parseInt(iframeStyles.getPropertyValue("padding-top")) || 0;
|
||||
const borderWidthLeft = parseInt(iframeStyles.getPropertyValue("border-left-width")) || 0;
|
||||
const borderWidthTop = parseInt(iframeStyles.getPropertyValue("border-top-width")) || 0;
|
||||
|
||||
if (!iframeRect || !iframeRectHasSize || !iframeElement.isConnected) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
url: subFrameUrl,
|
||||
frameId,
|
||||
@@ -1525,6 +1530,10 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
||||
subFrameData.frameId,
|
||||
);
|
||||
|
||||
if (!subFrameOffsets) {
|
||||
return;
|
||||
}
|
||||
|
||||
subFrameData.top += subFrameOffsets.top;
|
||||
subFrameData.left += subFrameOffsets.left;
|
||||
|
||||
@@ -1657,10 +1666,6 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
||||
globalThis.addEventListener(EVENTS.RESIZE, repositionHandler);
|
||||
}
|
||||
|
||||
private shouldRepositionSubFrameInlineMenuOnScroll = async () => {
|
||||
return await this.sendExtensionMessage("shouldRepositionSubFrameInlineMenuOnScroll");
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the listeners that facilitate repositioning
|
||||
* the overlay elements on scroll or resize.
|
||||
|
||||
Reference in New Issue
Block a user