mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 08:43:33 +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 defaultWindowReadyState = document.readyState;
|
||||||
const defaultDocumentVisibilityState = document.visibilityState;
|
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", () => {
|
describe("AutofillOverlayContentService", () => {
|
||||||
let domQueryService: DomQueryService;
|
let domQueryService: DomQueryService;
|
||||||
let domElementVisibilityService: DomElementVisibilityService;
|
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 () => {
|
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(
|
sendMockExtensionMessage(
|
||||||
{
|
{
|
||||||
command: "getSubFrameOffsets",
|
command: "getSubFrameOffsets",
|
||||||
@@ -2270,6 +2285,9 @@ describe("AutofillOverlayContentService", () => {
|
|||||||
});
|
});
|
||||||
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
||||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||||
|
jest
|
||||||
|
.spyOn(iframe, "getBoundingClientRect")
|
||||||
|
.mockReturnValue(mockRect({ width: 1, height: 1, left: 2, top: 2 }));
|
||||||
const subFrameData = {
|
const subFrameData = {
|
||||||
url: "https://example.com/",
|
url: "https://example.com/",
|
||||||
frameId: 10,
|
frameId: 10,
|
||||||
@@ -2305,6 +2323,9 @@ describe("AutofillOverlayContentService", () => {
|
|||||||
it("posts the calculated sub frame data to the background", async () => {
|
it("posts the calculated sub frame data to the background", async () => {
|
||||||
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
document.body.innerHTML = `<iframe id="subframe" src="https://example.com/"></iframe>`;
|
||||||
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
const iframe = document.querySelector("iframe") as HTMLIFrameElement;
|
||||||
|
jest
|
||||||
|
.spyOn(iframe, "getBoundingClientRect")
|
||||||
|
.mockReturnValue(mockRect({ width: 1, height: 1, left: 2, top: 2 }));
|
||||||
const subFrameData = {
|
const subFrameData = {
|
||||||
url: "https://example.com/",
|
url: "https://example.com/",
|
||||||
frameId: 10,
|
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", () => {
|
describe("checkMostRecentlyFocusedFieldHasValue message handler", () => {
|
||||||
it("returns true if the most recently focused field has a truthy value", async () => {
|
it("returns true if the most recently focused field has a truthy value", async () => {
|
||||||
autofillOverlayContentService["mostRecentlyFocusedField"] = mock<
|
autofillOverlayContentService["mostRecentlyFocusedField"] = mock<
|
||||||
|
|||||||
@@ -1485,12 +1485,17 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
|||||||
frameId?: number,
|
frameId?: number,
|
||||||
): SubFrameOffsetData {
|
): SubFrameOffsetData {
|
||||||
const iframeRect = iframeElement.getBoundingClientRect();
|
const iframeRect = iframeElement.getBoundingClientRect();
|
||||||
|
const iframeRectHasSize = iframeRect.width > 0 && iframeRect.height > 0;
|
||||||
const iframeStyles = globalThis.getComputedStyle(iframeElement);
|
const iframeStyles = globalThis.getComputedStyle(iframeElement);
|
||||||
const paddingLeft = parseInt(iframeStyles.getPropertyValue("padding-left")) || 0;
|
const paddingLeft = parseInt(iframeStyles.getPropertyValue("padding-left")) || 0;
|
||||||
const paddingTop = parseInt(iframeStyles.getPropertyValue("padding-top")) || 0;
|
const paddingTop = parseInt(iframeStyles.getPropertyValue("padding-top")) || 0;
|
||||||
const borderWidthLeft = parseInt(iframeStyles.getPropertyValue("border-left-width")) || 0;
|
const borderWidthLeft = parseInt(iframeStyles.getPropertyValue("border-left-width")) || 0;
|
||||||
const borderWidthTop = parseInt(iframeStyles.getPropertyValue("border-top-width")) || 0;
|
const borderWidthTop = parseInt(iframeStyles.getPropertyValue("border-top-width")) || 0;
|
||||||
|
|
||||||
|
if (!iframeRect || !iframeRectHasSize || !iframeElement.isConnected) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: subFrameUrl,
|
url: subFrameUrl,
|
||||||
frameId,
|
frameId,
|
||||||
@@ -1525,6 +1530,10 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
|||||||
subFrameData.frameId,
|
subFrameData.frameId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!subFrameOffsets) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
subFrameData.top += subFrameOffsets.top;
|
subFrameData.top += subFrameOffsets.top;
|
||||||
subFrameData.left += subFrameOffsets.left;
|
subFrameData.left += subFrameOffsets.left;
|
||||||
|
|
||||||
@@ -1657,10 +1666,6 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ
|
|||||||
globalThis.addEventListener(EVENTS.RESIZE, repositionHandler);
|
globalThis.addEventListener(EVENTS.RESIZE, repositionHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private shouldRepositionSubFrameInlineMenuOnScroll = async () => {
|
|
||||||
return await this.sendExtensionMessage("shouldRepositionSubFrameInlineMenuOnScroll");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the listeners that facilitate repositioning
|
* Removes the listeners that facilitate repositioning
|
||||||
* the overlay elements on scroll or resize.
|
* the overlay elements on scroll or resize.
|
||||||
|
|||||||
Reference in New Issue
Block a user