feat: customize border radius of Views (#42320)

* feat: add View#setBorderRadius

test: initial setBorderRadius tests

fix: robustly set border radius

chore: add PAUSE_CAPTURE_TESTS for easier screencap dev

feat: add view border radius support

test: view border radius

refactor: cleanup view code

* maybe delay capture to fix tests?

* refactor: retry screen captures in an attempt to fix flakiness

* refactor: ScreenCapture constructor no longer async

* increase screen capture timeout, feels a little short

* refactor: move rounded rect util into chromium_src

* skip some capture tests on mas
This commit is contained in:
Sam Maddock 2024-07-16 20:16:25 -04:00 committed by GitHub
parent cbd11bb605
commit 778d3098a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 261 additions and 90 deletions

View file

@ -1,10 +1,10 @@
import { closeAllWindows } from './lib/window-helpers';
import { expect } from 'chai';
import { BaseWindow, View, WebContentsView, webContents } from 'electron/main';
import { BaseWindow, BrowserWindow, View, WebContentsView, webContents, screen } from 'electron/main';
import { once } from 'node:events';
import { defer } from './lib/spec-helpers';
import { BrowserWindow } from 'electron';
import { closeAllWindows } from './lib/window-helpers';
import { defer, ifdescribe } from './lib/spec-helpers';
import { HexColors, ScreenCapture, hasCapturableScreen, nextFrameTime } from './lib/screen-helpers';
describe('WebContentsView', () => {
afterEach(closeAllWindows);
@ -224,4 +224,92 @@ describe('WebContentsView', () => {
expect(visibilityState).to.equal('visible');
});
});
describe('setBorderRadius', () => {
ifdescribe(hasCapturableScreen())('capture', () => {
let w: Electron.BaseWindow;
let v: Electron.WebContentsView;
let display: Electron.Display;
let corners: Electron.Point[];
const backgroundUrl = `data:text/html,<style>html{background:${encodeURIComponent(HexColors.GREEN)}}</style>`;
beforeEach(async () => {
display = screen.getPrimaryDisplay();
w = new BaseWindow({
...display.workArea,
show: true,
frame: false,
hasShadow: false,
backgroundColor: HexColors.BLUE,
roundedCorners: false
});
v = new WebContentsView();
w.setContentView(v);
v.setBorderRadius(100);
const readyForCapture = once(v.webContents, 'ready-to-show');
v.webContents.loadURL(backgroundUrl);
const inset = 10;
corners = [
{ x: display.workArea.x + inset, y: display.workArea.y + inset }, // top-left
{ x: display.workArea.x + display.workArea.width - inset, y: display.workArea.y + inset }, // top-right
{ x: display.workArea.x + display.workArea.width - inset, y: display.workArea.y + display.workArea.height - inset }, // bottom-right
{ x: display.workArea.x + inset, y: display.workArea.y + display.workArea.height - inset } // bottom-left
];
await readyForCapture;
});
afterEach(() => {
w.destroy();
w = v = null!;
});
it('should render with cutout corners', async () => {
const screenCapture = new ScreenCapture(display);
for (const corner of corners) {
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner);
}
// Center should be WebContents page background color
await screenCapture.expectColorAtCenterMatches(HexColors.GREEN);
});
it('should allow resetting corners', async () => {
const corner = corners[0];
v.setBorderRadius(0);
await nextFrameTime();
const screenCapture = new ScreenCapture(display);
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.GREEN, () => corner);
await screenCapture.expectColorAtCenterMatches(HexColors.GREEN);
});
it('should render when set before attached', async () => {
v = new WebContentsView();
v.setBorderRadius(100); // must set before
w.setContentView(v);
const readyForCapture = once(v.webContents, 'ready-to-show');
v.webContents.loadURL(backgroundUrl);
await readyForCapture;
const corner = corners[0];
const screenCapture = new ScreenCapture(display);
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner);
await screenCapture.expectColorAtCenterMatches(HexColors.GREEN);
});
});
it('should allow setting when not attached', async () => {
const v = new WebContentsView();
v.setBorderRadius(100);
});
});
});