Skip to content

Commit 30aca48

Browse files
committed
Added iframe mocks support.
1 parent d87b11e commit 30aca48

File tree

10 files changed

+234
-6
lines changed

10 files changed

+234
-6
lines changed

Diff for: lib/testcase/visualdiff.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Page } from '@playwright/test';
12
export declare function defineVisualDiffConfig(cases: VisualDiffUrlConfig): VisualDiffTestCases;
23
export declare function defaultTestFunction(testCase: VisualDiff, group: VisualDiffGroup): ({ page, context }: {
34
page: any;
@@ -40,6 +41,12 @@ export type VisualDiffGroup = BaseVisualDiff & {
4041
pathPrefix?: string;
4142
testCases: VisualDiff[];
4243
};
44+
export interface MockableConstructor {
45+
new (): Mockable;
46+
}
47+
export interface Mockable {
48+
mock(page: Page): Promise<void>;
49+
}
4350
/**
4451
* An individual test case.
4552
*/
@@ -51,6 +58,7 @@ export type BaseVisualDiff = {
5158
description?: string;
5259
representativeUrl?: string;
5360
skip?: SkipTest;
61+
mockClass?: MockableConstructor | void;
5462
};
5563
/**
5664
* A declaration that a test should be skipped.

Diff for: lib/testcase/visualdiff.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,18 @@ function defaultTestFunction(testCase, group) {
4848
var _this = this;
4949
// @ts-ignore
5050
return function (_a, testInfo_1) { return __awaiter(_this, [_a, testInfo_1], void 0, function (_b, testInfo) {
51-
var representativeUrl, path;
51+
var mock, representativeUrl, path;
5252
var page = _b.page, context = _b.context;
5353
return __generator(this, function (_c) {
5454
switch (_c.label) {
5555
case 0:
56+
if (!(testCase.mockClass != undefined)) return [3 /*break*/, 2];
57+
mock = new testCase.mockClass;
58+
return [4 /*yield*/, mock.mock(page)];
59+
case 1:
60+
_c.sent();
61+
_c.label = 2;
62+
case 2:
5663
// Log any errors to the Playwright console too.
5764
context.on('weberror', function (webError) { return console.log(webError.error()); });
5865
testInfo.annotations.push({
@@ -77,10 +84,10 @@ function defaultTestFunction(testCase, group) {
7784
path = group.pathPrefix + path;
7885
}
7986
return [4 /*yield*/, page.goto(path)];
80-
case 1:
87+
case 3:
8188
_c.sent();
8289
return [4 /*yield*/, (0, util_1.takeAccessibleScreenshot)(page, testInfo, { fullPage: true })];
83-
case 2:
90+
case 4:
8491
_c.sent();
8592
return [2 /*return*/];
8693
}

Diff for: lib/util/mock/mock.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Page } from '@playwright/test';
2+
import { Mockable } from "../../testcase";
3+
export declare class Mock implements Mockable {
4+
mock(page: Page): Promise<void>;
5+
}

Diff for: lib/util/mock/mock.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
var __generator = (this && this.__generator) || function (thisArg, body) {
12+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14+
function verb(n) { return function (v) { return step([n, v]); }; }
15+
function step(op) {
16+
if (f) throw new TypeError("Generator is already executing.");
17+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
18+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19+
if (y = 0, t) op = [op[0] & 2, t.value];
20+
switch (op[0]) {
21+
case 0: case 1: t = op; break;
22+
case 4: _.label++; return { value: op[1], done: false };
23+
case 5: _.label++; y = op[1]; op = [0]; continue;
24+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
25+
default:
26+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30+
if (t[2]) _.ops.pop();
31+
_.trys.pop(); continue;
32+
}
33+
op = body.call(thisArg, _);
34+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36+
}
37+
};
38+
Object.defineProperty(exports, "__esModule", { value: true });
39+
exports.Mock = void 0;
40+
var youtube_1 = require("./youtube");
41+
var Mock = /** @class */ (function () {
42+
function Mock() {
43+
}
44+
Mock.prototype.mock = function (page) {
45+
var _this = this;
46+
var f = function (page) { return __awaiter(_this, void 0, void 0, function () {
47+
var youtube;
48+
return __generator(this, function (_a) {
49+
switch (_a.label) {
50+
case 0:
51+
youtube = new youtube_1.Youtube();
52+
return [4 /*yield*/, youtube.mock(page)];
53+
case 1:
54+
_a.sent();
55+
return [2 /*return*/];
56+
}
57+
});
58+
}); };
59+
return f(page);
60+
};
61+
return Mock;
62+
}());
63+
exports.Mock = Mock;

Diff for: lib/util/mock/youtube.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Page } from '@playwright/test';
2+
import { Mockable } from "../../testcase";
3+
export declare class Youtube implements Mockable {
4+
mock(page: Page): Promise<void>;
5+
}

Diff for: lib/util/mock/youtube.js

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"use strict";
2+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4+
return new (P || (P = Promise))(function (resolve, reject) {
5+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8+
step((generator = generator.apply(thisArg, _arguments || [])).next());
9+
});
10+
};
11+
var __generator = (this && this.__generator) || function (thisArg, body) {
12+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14+
function verb(n) { return function (v) { return step([n, v]); }; }
15+
function step(op) {
16+
if (f) throw new TypeError("Generator is already executing.");
17+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
18+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19+
if (y = 0, t) op = [op[0] & 2, t.value];
20+
switch (op[0]) {
21+
case 0: case 1: t = op; break;
22+
case 4: _.label++; return { value: op[1], done: false };
23+
case 5: _.label++; y = op[1]; op = [0]; continue;
24+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
25+
default:
26+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30+
if (t[2]) _.ops.pop();
31+
_.trys.pop(); continue;
32+
}
33+
op = body.call(thisArg, _);
34+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36+
}
37+
};
38+
Object.defineProperty(exports, "__esModule", { value: true });
39+
exports.Youtube = void 0;
40+
var Youtube = /** @class */ (function () {
41+
function Youtube() {
42+
}
43+
Youtube.prototype.mock = function (page) {
44+
return __awaiter(this, void 0, void 0, function () {
45+
var ytEmbedUrl;
46+
var _this = this;
47+
return __generator(this, function (_a) {
48+
switch (_a.label) {
49+
case 0:
50+
ytEmbedUrl = new RegExp('www\.youtube\.com', 'i');
51+
return [4 /*yield*/, page.route(ytEmbedUrl, function (route) { return __awaiter(_this, void 0, void 0, function () {
52+
return __generator(this, function (_a) {
53+
switch (_a.label) {
54+
case 0: return [4 /*yield*/, route.fulfill({
55+
contentType: 'text/html',
56+
body: "\n<html>\n<head>\n <title>Youtube Video Mock</title>\n <style>\n body {\n color: white;\n background-color: darkred;\n }\n div {\n position: absolute;\n top: 50%;\n left: 50%;\n margin: 0;\n transform: translate(-50%, -50%);\n font-size: xxx-large;\n text-align: center;\n }\n </style>\n</head>\n<body>\n <div>Youtube Video Mock</div>\n</body>\n</html>\n",
57+
})];
58+
case 1:
59+
_a.sent();
60+
return [2 /*return*/];
61+
}
62+
});
63+
}); })];
64+
case 1:
65+
_a.sent();
66+
return [2 /*return*/];
67+
}
68+
});
69+
});
70+
};
71+
return Youtube;
72+
}());
73+
exports.Youtube = Youtube;

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
},
1818
"devDependencies": {
1919
"typescript": "^5.2.2"
20-
}
20+
},
21+
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
2122
}

Diff for: src/testcase/visualdiff.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {test, WebError} from '@playwright/test';
1+
import {Page, test, WebError} from '@playwright/test';
22

33
import {takeAccessibleScreenshot} from "../util";
44

@@ -9,8 +9,12 @@ export function defineVisualDiffConfig(cases: VisualDiffUrlConfig) {
99
export function defaultTestFunction(testCase: VisualDiff, group: VisualDiffGroup) {
1010
// @ts-ignore
1111
return async ({page, context}, testInfo) => {
12-
// Log any errors to the Playwright console too.
12+
if (testCase.mockClass != undefined) {
13+
const mock = new testCase.mockClass;
14+
await mock.mock(page);
15+
}
1316

17+
// Log any errors to the Playwright console too.
1418
context.on('weberror', (webError: WebError) => console.log(webError.error()));
1519
testInfo.annotations.push({
1620
type: 'Description',
@@ -130,6 +134,13 @@ export type VisualDiffGroup = BaseVisualDiff & {
130134
testCases: VisualDiff[],
131135
}
132136

137+
export interface MockableConstructor {
138+
new (): Mockable;
139+
}
140+
export interface Mockable {
141+
mock(page: Page): Promise<void>
142+
}
143+
133144
/**
134145
* An individual test case.
135146
*/
@@ -147,6 +158,7 @@ export type BaseVisualDiff = {
147158
representativeUrl?: string,
148159
// Allow skipping of this test.
149160
skip?: SkipTest,
161+
mockClass?: MockableConstructor | void
150162
}
151163

152164
/**

Diff for: src/util/mock/mock.ts

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {Page} from '@playwright/test';
2+
import {Mockable} from "../../testcase";
3+
import {Youtube} from "./youtube";
4+
5+
export class Mock implements Mockable{
6+
7+
mock(page: Page): Promise<void> {
8+
const f = async(page: Page): Promise<void> => {
9+
const youtube = new Youtube();
10+
await youtube.mock(page);
11+
}
12+
return f(page);
13+
}
14+
}

Diff for: src/util/mock/youtube.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {Page} from '@playwright/test';
2+
import {Mockable} from "../../testcase";
3+
4+
export class Youtube implements Mockable{
5+
6+
public async mock(page: Page): Promise<void> {
7+
const ytEmbedUrl = new RegExp('www\.youtube\.com', 'i');
8+
await page.route(ytEmbedUrl, async route => {
9+
await route.fulfill({
10+
contentType: 'text/html',
11+
body: `
12+
<html>
13+
<head>
14+
<title>Youtube Video Mock</title>
15+
<style>
16+
body {
17+
color: white;
18+
background-color: darkred;
19+
}
20+
div {
21+
position: absolute;
22+
top: 50%;
23+
left: 50%;
24+
margin: 0;
25+
transform: translate(-50%, -50%);
26+
font-size: xxx-large;
27+
text-align: center;
28+
}
29+
</style>
30+
</head>
31+
<body>
32+
<div>Youtube Video Mock</div>
33+
</body>
34+
</html>
35+
`,
36+
});
37+
});
38+
}
39+
40+
}

0 commit comments

Comments
 (0)