2020-08-11 07:22:57 +03:00
|
|
|
/**
|
|
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2020-08-17 05:19:52 +03:00
|
|
|
|
2020-10-12 19:16:02 +03:00
|
|
|
import { it, expect, describe } from './fixtures';
|
2020-08-14 17:22:54 +03:00
|
|
|
import fs from 'fs';
|
|
|
|
import path from 'path';
|
2020-09-30 04:52:30 +03:00
|
|
|
import { spawnSync } from 'child_process';
|
|
|
|
import { PNG } from 'pngjs';
|
2021-02-09 03:02:49 +03:00
|
|
|
import { Registry } from '../src/utils/registry';
|
2020-09-30 04:52:30 +03:00
|
|
|
|
2021-02-09 03:02:49 +03:00
|
|
|
const registry = new Registry(path.join(__dirname, '..'));
|
|
|
|
const ffmpeg = registry.executablePath('ffmpeg') || '';
|
2020-09-30 04:52:30 +03:00
|
|
|
|
|
|
|
export class VideoPlayer {
|
|
|
|
fileName: string;
|
|
|
|
output: string;
|
|
|
|
duration: number;
|
|
|
|
frames: number;
|
|
|
|
videoWidth: number;
|
|
|
|
videoHeight: number;
|
|
|
|
cache = new Map<number, PNG>();
|
|
|
|
|
|
|
|
constructor(fileName: string) {
|
|
|
|
this.fileName = fileName;
|
2020-10-23 20:33:58 +03:00
|
|
|
// Force output frame rate to 25 fps as otherwise it would produce one image per timebase unit
|
|
|
|
// which is 1 / (25 * 1000).
|
|
|
|
this.output = spawnSync(ffmpeg, ['-i', this.fileName, '-r', '25', `${this.fileName}-%03d.png`]).stderr.toString();
|
2020-09-30 04:52:30 +03:00
|
|
|
|
|
|
|
const lines = this.output.split('\n');
|
|
|
|
let framesLine = lines.find(l => l.startsWith('frame='))!;
|
2021-02-08 21:59:48 +03:00
|
|
|
if (!framesLine)
|
|
|
|
throw new Error(`No frame data in the output:\n${this.output}`);
|
2020-09-30 04:52:30 +03:00
|
|
|
framesLine = framesLine.substring(framesLine.lastIndexOf('frame='));
|
|
|
|
const framesMatch = framesLine.match(/frame=\s+(\d+)/);
|
|
|
|
const streamLine = lines.find(l => l.trim().startsWith('Stream #0:0'));
|
|
|
|
const resolutionMatch = streamLine.match(/, (\d+)x(\d+),/);
|
|
|
|
const durationMatch = lines.find(l => l.trim().startsWith('Duration'))!.match(/Duration: (\d+):(\d\d):(\d\d.\d\d)/);
|
|
|
|
this.duration = (((parseInt(durationMatch![1], 10) * 60) + parseInt(durationMatch![2], 10)) * 60 + parseFloat(durationMatch![3])) * 1000;
|
|
|
|
this.frames = parseInt(framesMatch![1], 10);
|
|
|
|
this.videoWidth = parseInt(resolutionMatch![1], 10);
|
|
|
|
this.videoHeight = parseInt(resolutionMatch![2], 10);
|
|
|
|
}
|
2020-08-11 07:22:57 +03:00
|
|
|
|
2020-09-30 04:52:30 +03:00
|
|
|
seekFirstNonEmptyFrame(offset?: { x: number, y: number } | undefined): PNG | undefined {
|
|
|
|
for (let f = 1; f <= this.frames; ++f) {
|
|
|
|
const frame = this.frame(f, { x: 0, y: 0 });
|
|
|
|
let hasColor = false;
|
|
|
|
for (let i = 0; i < frame.data.length; i += 4) {
|
|
|
|
if (frame.data[i + 0] < 230 || frame.data[i + 1] < 230 || frame.data[i + 2] < 230) {
|
|
|
|
hasColor = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hasColor)
|
|
|
|
return this.frame(f, offset);
|
|
|
|
}
|
|
|
|
}
|
2020-09-19 03:36:43 +03:00
|
|
|
|
2020-09-30 04:52:30 +03:00
|
|
|
seekLastFrame(offset?: { x: number, y: number }): PNG {
|
|
|
|
return this.frame(this.frames, offset);
|
|
|
|
}
|
2020-09-19 03:36:43 +03:00
|
|
|
|
2020-09-30 04:52:30 +03:00
|
|
|
frame(frame: number, offset = { x: 10, y: 10 }): PNG {
|
|
|
|
if (!this.cache.has(frame)) {
|
|
|
|
const gap = '0'.repeat(3 - String(frame).length);
|
|
|
|
const buffer = fs.readFileSync(`${this.fileName}-${gap}${frame}.png`);
|
|
|
|
this.cache.set(frame, PNG.sync.read(buffer));
|
|
|
|
}
|
|
|
|
const decoded = this.cache.get(frame);
|
|
|
|
const dst = new PNG({ width: 10, height: 10 });
|
|
|
|
PNG.bitblt(decoded, dst, offset.x, offset.y, 10, 10, 0, 0);
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 01:04:44 +03:00
|
|
|
|
2020-08-12 20:18:41 +03:00
|
|
|
function almostRed(r, g, b, alpha) {
|
2021-01-06 07:31:50 +03:00
|
|
|
expect(r).toBeGreaterThan(185);
|
|
|
|
expect(g).toBeLessThan(70);
|
|
|
|
expect(b).toBeLessThan(70);
|
2020-08-12 20:18:41 +03:00
|
|
|
expect(alpha).toBe(255);
|
|
|
|
}
|
|
|
|
|
|
|
|
function almostBlack(r, g, b, alpha) {
|
2021-01-06 07:31:50 +03:00
|
|
|
expect(r).toBeLessThan(70);
|
|
|
|
expect(g).toBeLessThan(70);
|
|
|
|
expect(b).toBeLessThan(70);
|
2020-08-12 20:18:41 +03:00
|
|
|
expect(alpha).toBe(255);
|
|
|
|
}
|
|
|
|
|
2021-01-06 07:31:50 +03:00
|
|
|
function almostGray(r, g, b, alpha) {
|
2020-09-30 04:52:30 +03:00
|
|
|
expect(r).toBeGreaterThan(70);
|
|
|
|
expect(g).toBeGreaterThan(70);
|
|
|
|
expect(b).toBeGreaterThan(70);
|
2021-01-06 07:31:50 +03:00
|
|
|
expect(r).toBeLessThan(185);
|
|
|
|
expect(g).toBeLessThan(185);
|
|
|
|
expect(b).toBeLessThan(185);
|
2020-08-12 20:18:41 +03:00
|
|
|
expect(alpha).toBe(255);
|
|
|
|
}
|
|
|
|
|
2020-09-30 04:52:30 +03:00
|
|
|
function expectAll(pixels: Buffer, rgbaPredicate) {
|
2020-08-28 14:20:29 +03:00
|
|
|
const checkPixel = i => {
|
2020-08-12 20:18:41 +03:00
|
|
|
const r = pixels[i];
|
|
|
|
const g = pixels[i + 1];
|
|
|
|
const b = pixels[i + 2];
|
|
|
|
const alpha = pixels[i + 3];
|
|
|
|
rgbaPredicate(r, g, b, alpha);
|
2020-08-28 14:20:29 +03:00
|
|
|
};
|
2020-08-12 20:18:41 +03:00
|
|
|
try {
|
2020-08-28 14:20:29 +03:00
|
|
|
for (let i = 0, n = pixels.length; i < n; i += 4)
|
2020-08-12 20:18:41 +03:00
|
|
|
checkPixel(i);
|
2020-08-28 14:20:29 +03:00
|
|
|
} catch (e) {
|
2020-08-12 20:18:41 +03:00
|
|
|
// Log pixel values on failure.
|
2020-10-23 20:33:58 +03:00
|
|
|
e.message += `\n\nActual pixels=[${pixels.join(',')}]`;
|
2020-08-12 20:18:41 +03:00
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-30 04:52:30 +03:00
|
|
|
function findVideos(videoDir: string) {
|
|
|
|
const files = fs.readdirSync(videoDir);
|
2020-09-19 03:36:43 +03:00
|
|
|
return files.filter(file => file.endsWith('webm')).map(file => path.join(videoDir, file));
|
|
|
|
}
|
|
|
|
|
2020-11-08 05:21:26 +03:00
|
|
|
function expectRedFrames(videoFile: string, size: { width: number, height: number }) {
|
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
const duration = videoPlayer.duration;
|
|
|
|
expect(duration).toBeGreaterThan(0);
|
|
|
|
|
|
|
|
expect(videoPlayer.videoWidth).toBe(size.width);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(size.height);
|
|
|
|
|
|
|
|
{
|
|
|
|
const pixels = videoPlayer.seekLastFrame().data;
|
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const pixels = videoPlayer.seekLastFrame({ x: size.width - 20, y: 0 }).data;
|
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-29 01:45:09 +03:00
|
|
|
describe('screencast', suite => {
|
2020-08-31 23:18:19 +03:00
|
|
|
suite.slow();
|
2020-08-29 01:45:09 +03:00
|
|
|
}, () => {
|
2020-10-01 21:06:19 +03:00
|
|
|
it('videoSize should require videosPath', async ({browser}) => {
|
|
|
|
const error = await browser.newContext({ videoSize: { width: 100, height: 100 } }).catch(e => e);
|
|
|
|
expect(error.message).toContain('"videoSize" option requires "videosPath" to be specified');
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|
|
|
|
|
2020-11-03 06:42:05 +03:00
|
|
|
it('should work with old options', async ({browser, testInfo}) => {
|
2020-10-06 03:03:24 +03:00
|
|
|
const videosPath = testInfo.outputPath('');
|
2020-10-20 00:35:18 +03:00
|
|
|
const size = { width: 450, height: 240 };
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-10-01 21:06:19 +03:00
|
|
|
videosPath,
|
2020-09-30 04:52:30 +03:00
|
|
|
viewport: size,
|
|
|
|
videoSize: size
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|
2020-09-12 04:58:53 +03:00
|
|
|
const page = await context.newPage();
|
|
|
|
|
2020-08-31 23:18:19 +03:00
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
2020-09-03 01:21:58 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-08-31 23:18:19 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-11-08 05:21:26 +03:00
|
|
|
expectRedFrames(videoFile, size);
|
2020-11-03 06:42:05 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should throw without recordVideo.dir', async ({ browser }) => {
|
|
|
|
const error = await browser.newContext({ recordVideo: {} as any }).catch(e => e);
|
|
|
|
expect(error.message).toContain('recordVideo.dir: expected string, got undefined');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should capture static page', async ({browser, testInfo}) => {
|
|
|
|
const size = { width: 450, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
size
|
|
|
|
},
|
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
|
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
|
|
await context.close();
|
|
|
|
|
|
|
|
const videoFile = await page.video().path();
|
2020-11-08 05:21:26 +03:00
|
|
|
expectRedFrames(videoFile, size);
|
2020-08-31 23:18:19 +03:00
|
|
|
});
|
|
|
|
|
2020-10-15 00:10:35 +03:00
|
|
|
it('should expose video path', async ({browser, testInfo}) => {
|
2020-10-14 08:15:51 +03:00
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
2020-10-14 08:15:51 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
|
|
|
const path = await page.video()!.path();
|
|
|
|
expect(path).toContain(videosPath);
|
2020-10-15 00:10:35 +03:00
|
|
|
await context.close();
|
|
|
|
expect(fs.existsSync(path)).toBeTruthy();
|
2020-10-15 01:09:36 +03:00
|
|
|
});
|
|
|
|
|
2021-03-31 20:38:05 +03:00
|
|
|
it('should saveAs video', async ({browser, testInfo}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
|
|
|
await page.waitForTimeout(1000);
|
|
|
|
await context.close();
|
|
|
|
|
|
|
|
const saveAsPath = testInfo.outputPath('my-video.webm');
|
|
|
|
await page.video().saveAs(saveAsPath);
|
|
|
|
expect(fs.existsSync(saveAsPath)).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('saveAs should throw when no video frames', async ({browser, browserName, testInfo}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
|
|
|
|
const page = await context.newPage();
|
|
|
|
const [popup] = await Promise.all([
|
|
|
|
page.context().waitForEvent('page'),
|
|
|
|
page.evaluate(() => {
|
|
|
|
const win = window.open('about:blank');
|
|
|
|
win.close();
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
await page.close();
|
|
|
|
|
|
|
|
const saveAsPath = testInfo.outputPath('my-video.webm');
|
|
|
|
const error = await popup.video().saveAs(saveAsPath).catch(e => e);
|
|
|
|
// WebKit pauses renderer before win.close() and actually writes something.
|
|
|
|
if (browserName === 'webkit')
|
|
|
|
expect(fs.existsSync(saveAsPath)).toBeTruthy();
|
|
|
|
else
|
|
|
|
expect(error.message).toContain('Page did not produce any video frames');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should delete video', async ({browser, testInfo}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
const deletePromise = page.video().delete();
|
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
|
|
|
await page.waitForTimeout(1000);
|
|
|
|
await context.close();
|
|
|
|
|
|
|
|
const videoPath = await page.video().path();
|
|
|
|
await deletePromise;
|
|
|
|
expect(fs.existsSync(videoPath)).toBeFalsy();
|
|
|
|
});
|
|
|
|
|
2020-10-15 01:09:36 +03:00
|
|
|
it('should expose video path blank page', async ({browser, testInfo}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
2020-10-15 01:09:36 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
const path = await page.video()!.path();
|
|
|
|
expect(path).toContain(videosPath);
|
|
|
|
await context.close();
|
|
|
|
expect(fs.existsSync(path)).toBeTruthy();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should expose video path blank popup', async ({browser, testInfo}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
|
|
|
size
|
|
|
|
},
|
2020-10-15 01:09:36 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
const [popup] = await Promise.all([
|
|
|
|
page.waitForEvent('popup'),
|
|
|
|
page.evaluate('window.open("about:blank")')
|
|
|
|
]);
|
|
|
|
const path = await popup.video()!.path();
|
|
|
|
expect(path).toContain(videosPath);
|
|
|
|
await context.close();
|
|
|
|
expect(fs.existsSync(path)).toBeTruthy();
|
2020-10-14 08:15:51 +03:00
|
|
|
});
|
|
|
|
|
2020-10-06 03:03:24 +03:00
|
|
|
it('should capture navigation', async ({browser, server, testInfo}) => {
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
size: { width: 1280, height: 720 }
|
|
|
|
},
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|
2020-09-12 04:58:53 +03:00
|
|
|
const page = await context.newPage();
|
|
|
|
|
2020-08-28 23:53:47 +03:00
|
|
|
await page.goto(server.PREFIX + '/background-color.html#rgb(0,0,0)');
|
2020-09-03 01:21:58 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-08-28 23:53:47 +03:00
|
|
|
await page.goto(server.CROSS_PROCESS_PREFIX + '/background-color.html#rgb(100,100,100)');
|
2020-09-03 01:21:58 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-08-28 23:53:47 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-09-30 04:52:30 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
const duration = videoPlayer.duration;
|
2020-08-28 23:53:47 +03:00
|
|
|
expect(duration).toBeGreaterThan(0);
|
|
|
|
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekFirstNonEmptyFrame().data;
|
2020-08-28 23:53:47 +03:00
|
|
|
expectAll(pixels, almostBlack);
|
|
|
|
}
|
2020-08-25 03:23:54 +03:00
|
|
|
|
2020-08-28 23:53:47 +03:00
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame().data;
|
2021-01-06 07:31:50 +03:00
|
|
|
expectAll(pixels, almostGray);
|
2020-08-28 23:53:47 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-01-06 07:31:50 +03:00
|
|
|
it('should capture css transformation', (test, { headful, browserName, platform }) => {
|
2020-09-27 02:05:58 +03:00
|
|
|
test.fixme(headful, 'Fails on headful');
|
2021-01-06 07:31:50 +03:00
|
|
|
test.fixme(browserName === 'webkit' && platform === 'win32', 'Fails on headful');
|
2020-10-06 03:03:24 +03:00
|
|
|
}, async ({browser, server, testInfo}) => {
|
2020-09-30 04:52:30 +03:00
|
|
|
const size = { width: 320, height: 240 };
|
2020-09-02 20:40:50 +03:00
|
|
|
// Set viewport equal to screencast frame size to avoid scaling.
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
size,
|
|
|
|
},
|
2020-09-19 03:36:43 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
2020-09-12 04:58:53 +03:00
|
|
|
const page = await context.newPage();
|
|
|
|
|
2020-08-28 23:53:47 +03:00
|
|
|
await page.goto(server.PREFIX + '/rotate-z.html');
|
2020-09-03 01:21:58 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-08-28 23:53:47 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-09-30 04:52:30 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
const duration = videoPlayer.duration;
|
2020-08-28 23:53:47 +03:00
|
|
|
expect(duration).toBeGreaterThan(0);
|
|
|
|
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame({ x: 95, y: 45 }).data;
|
2020-08-28 23:53:47 +03:00
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-10-06 03:03:24 +03:00
|
|
|
it('should work for popups', async ({browser, testInfo, server}) => {
|
|
|
|
const videosPath = testInfo.outputPath('');
|
2020-11-08 05:21:26 +03:00
|
|
|
const size = { width: 450, height: 240 };
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: videosPath,
|
2020-11-08 05:21:26 +03:00
|
|
|
size,
|
2020-11-03 06:42:05 +03:00
|
|
|
},
|
2020-11-08 05:21:26 +03:00
|
|
|
viewport: size,
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|
2020-09-01 01:21:02 +03:00
|
|
|
|
2020-09-09 03:01:00 +03:00
|
|
|
const page = await context.newPage();
|
2020-09-05 08:37:38 +03:00
|
|
|
await page.goto(server.EMPTY_PAGE);
|
2020-11-08 05:21:26 +03:00
|
|
|
const [popup] = await Promise.all([
|
2020-09-19 03:36:43 +03:00
|
|
|
page.waitForEvent('popup'),
|
|
|
|
page.evaluate(() => { window.open('about:blank'); }),
|
2020-08-28 23:53:47 +03:00
|
|
|
]);
|
2020-11-08 05:21:26 +03:00
|
|
|
await popup.evaluate(() => document.body.style.backgroundColor = 'red');
|
2020-09-19 03:36:43 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
|
|
await context.close();
|
|
|
|
|
2020-11-08 05:21:26 +03:00
|
|
|
const pageVideoFile = await page.video().path();
|
|
|
|
const popupVideoFile = await popup.video().path();
|
|
|
|
expect(pageVideoFile).not.toEqual(popupVideoFile);
|
|
|
|
expectRedFrames(popupVideoFile, size);
|
|
|
|
|
2020-10-01 21:06:19 +03:00
|
|
|
const videoFiles = findVideos(videosPath);
|
2020-09-19 03:36:43 +03:00
|
|
|
expect(videoFiles.length).toBe(2);
|
2020-08-28 23:53:47 +03:00
|
|
|
});
|
2020-09-02 23:59:15 +03:00
|
|
|
|
2020-09-27 02:05:58 +03:00
|
|
|
it('should scale frames down to the requested size ', (test, parameters) => {
|
|
|
|
test.fixme(parameters.headful, 'Fails on headful');
|
2020-10-06 03:03:24 +03:00
|
|
|
}, async ({browser, testInfo, server}) => {
|
2020-09-12 04:58:53 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
// Set size to 1/2 of the viewport.
|
|
|
|
size: { width: 320, height: 240 },
|
|
|
|
},
|
2020-09-12 04:58:53 +03:00
|
|
|
viewport: {width: 640, height: 480},
|
|
|
|
});
|
|
|
|
const page = await context.newPage();
|
|
|
|
|
2020-09-02 23:59:15 +03:00
|
|
|
await page.goto(server.PREFIX + '/checkerboard.html');
|
|
|
|
// Update the picture to ensure enough frames are generated.
|
|
|
|
await page.$eval('.container', container => {
|
|
|
|
container.firstElementChild.classList.remove('red');
|
|
|
|
});
|
|
|
|
await new Promise(r => setTimeout(r, 300));
|
|
|
|
await page.$eval('.container', container => {
|
|
|
|
container.firstElementChild.classList.add('red');
|
|
|
|
});
|
2020-09-03 01:21:58 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-09-02 23:59:15 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-09-30 04:52:30 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
const duration = videoPlayer.duration;
|
2020-09-02 23:59:15 +03:00
|
|
|
expect(duration).toBeGreaterThan(0);
|
|
|
|
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame({x: 0, y: 0}).data;
|
2020-09-02 23:59:15 +03:00
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame({x: 300, y: 0}).data;
|
2021-01-06 07:31:50 +03:00
|
|
|
expectAll(pixels, almostGray);
|
2020-09-02 23:59:15 +03:00
|
|
|
}
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame({x: 0, y: 200}).data;
|
2021-01-06 07:31:50 +03:00
|
|
|
expectAll(pixels, almostGray);
|
2020-09-02 23:59:15 +03:00
|
|
|
}
|
|
|
|
{
|
2020-09-30 04:52:30 +03:00
|
|
|
const pixels = videoPlayer.seekLastFrame({x: 300, y: 200}).data;
|
2020-09-02 23:59:15 +03:00
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
});
|
2020-09-12 01:14:31 +03:00
|
|
|
|
2021-02-08 21:59:48 +03:00
|
|
|
it('should use viewport scaled down to fit into 800x800 as default size', async ({browser, testInfo}) => {
|
|
|
|
const size = {width: 1600, height: 1200};
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
},
|
2020-09-19 03:36:43 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
2020-09-12 01:14:31 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const page = await context.newPage();
|
2020-09-12 01:14:31 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-09-12 01:14:31 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-09-30 04:52:30 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
2021-02-08 21:59:48 +03:00
|
|
|
expect(videoPlayer.videoWidth).toBe(800);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(600);
|
2020-09-12 01:14:31 +03:00
|
|
|
});
|
|
|
|
|
2021-03-15 18:07:57 +03:00
|
|
|
it('should be 800x450 by default', async ({ browser, testInfo }) => {
|
2020-09-19 03:36:43 +03:00
|
|
|
const context = await browser.newContext({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
},
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|
2020-09-12 01:14:31 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const page = await context.newPage();
|
2020-09-12 01:14:31 +03:00
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
2020-09-19 03:36:43 +03:00
|
|
|
await context.close();
|
2020-09-12 01:14:31 +03:00
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-09-30 04:52:30 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
2021-02-08 21:59:48 +03:00
|
|
|
expect(videoPlayer.videoWidth).toBe(800);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(450);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should be 800x600 with null viewport', (test, { headful, browserName }) => {
|
|
|
|
test.fixme(browserName === 'firefox' && !headful, 'Fails in headless on bots');
|
|
|
|
}, async ({ browser, testInfo }) => {
|
|
|
|
const context = await browser.newContext({
|
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
},
|
|
|
|
viewport: null
|
|
|
|
});
|
|
|
|
|
|
|
|
const page = await context.newPage();
|
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
|
|
await context.close();
|
|
|
|
|
|
|
|
const videoFile = await page.video().path();
|
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
expect(videoPlayer.videoWidth).toBe(800);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(600);
|
2020-09-12 01:14:31 +03:00
|
|
|
});
|
2020-10-01 21:06:19 +03:00
|
|
|
|
2020-10-06 03:03:24 +03:00
|
|
|
it('should capture static page in persistent context', async ({launchPersistent, testInfo}) => {
|
2020-10-01 21:06:19 +03:00
|
|
|
const size = { width: 320, height: 240 };
|
|
|
|
const { context, page } = await launchPersistent({
|
2020-11-03 06:42:05 +03:00
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
size,
|
|
|
|
},
|
2020-10-01 21:06:19 +03:00
|
|
|
viewport: size,
|
|
|
|
});
|
|
|
|
|
|
|
|
await page.evaluate(() => document.body.style.backgroundColor = 'red');
|
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
|
|
await context.close();
|
|
|
|
|
2020-10-20 00:35:18 +03:00
|
|
|
const videoFile = await page.video().path();
|
2020-10-01 21:06:19 +03:00
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
const duration = videoPlayer.duration;
|
|
|
|
expect(duration).toBeGreaterThan(0);
|
|
|
|
|
|
|
|
expect(videoPlayer.videoWidth).toBe(320);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(240);
|
|
|
|
|
|
|
|
{
|
|
|
|
const pixels = videoPlayer.seekLastFrame().data;
|
|
|
|
expectAll(pixels, almostRed);
|
|
|
|
}
|
|
|
|
});
|
2021-02-11 00:37:27 +03:00
|
|
|
|
|
|
|
it('should emulate an iphone', (test, { browserName }) => {
|
|
|
|
test.skip(browserName === 'firefox', 'isMobile is not supported in Firefox');
|
|
|
|
}, async ({contextFactory, playwright, contextOptions, testInfo}) => {
|
|
|
|
const device = playwright.devices['iPhone 6'];
|
|
|
|
const context = await contextFactory({
|
|
|
|
...contextOptions,
|
|
|
|
...device,
|
|
|
|
recordVideo: {
|
|
|
|
dir: testInfo.outputPath(''),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const page = await context.newPage();
|
|
|
|
await new Promise(r => setTimeout(r, 1000));
|
|
|
|
await context.close();
|
|
|
|
|
|
|
|
const videoFile = await page.video().path();
|
|
|
|
const videoPlayer = new VideoPlayer(videoFile);
|
|
|
|
expect(videoPlayer.videoWidth).toBe(374);
|
|
|
|
expect(videoPlayer.videoHeight).toBe(666);
|
|
|
|
});
|
2020-09-19 03:36:43 +03:00
|
|
|
});
|