From 5a024040d788fc93185e0a34518197659b2018ca Mon Sep 17 00:00:00 2001
From: wangjinxin613 <1749574663@qq.com>
Date: Tue, 30 Jan 2024 19:25:25 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=88=AA=E5=9B=BE?=
=?UTF-8?q?=E5=AF=B9=E6=AF=94=E6=B5=8B=E8=AF=95=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +-
jest-setup.js | 26 +-
pages.json | 16 +-
.../webview-screenshot-comparison.test.js | 245 ++++++++++++++++++
.../webview-screenshot-comparison.uvue | 76 ++++++
.../webview-screenshot.test.js | 228 ++++++++++++++++
.../webview-screenshot.uvue | 57 ++++
7 files changed, 647 insertions(+), 4 deletions(-)
create mode 100644 pages/webview-screenshot-comparison/webview-screenshot-comparison.test.js
create mode 100644 pages/webview-screenshot-comparison/webview-screenshot-comparison.uvue
create mode 100644 pages/webview-screenshot/webview-screenshot.test.js
create mode 100644 pages/webview-screenshot/webview-screenshot.uvue
diff --git a/.gitignore b/.gitignore
index 83cafe1..e68bcae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ node_modules/
.project
unpackage/
.DS_Store
-.hbuilderx/
\ No newline at end of file
+.hbuilderx/
+__image_snapshots__/
\ No newline at end of file
diff --git a/jest-setup.js b/jest-setup.js
index 8299fe7..c5b8872 100644
--- a/jest-setup.js
+++ b/jest-setup.js
@@ -1,3 +1,25 @@
-const { toMatchImageSnapshot } = require('jest-image-snapshot')
+const path = require('path');
+const {
+ configureToMatchImageSnapshot
+} = require('jest-image-snapshot');
-expect.extend({ toMatchImageSnapshot })
+const hbuilderx_version = process.env.HX_Version
+const uniTestPlatformInfo = process.env.uniTestPlatformInfo ? process.env.uniTestPlatformInfo.replace(/\s/g,'_') : ''
+const folderName = `__image_snapshots__/${hbuilderx_version}/__${uniTestPlatformInfo}__`
+let environment = 'official'
+if(hbuilderx_version.includes('dev')){
+ environment = 'dev'
+}else if(hbuilderx_version.includes('alpha')){
+ environment = 'alpha'
+}
+const baseFolderName = `__image_snapshots__/base/${environment}/__${uniTestPlatformInfo}__`
+
+expect.extend({
+ toMatchImageSnapshot: configureToMatchImageSnapshot({
+ customSnapshotIdentifier(args) {
+ return args.currentTestName.replace(/\//g, '-').replace(' ', '-');
+ },
+ customSnapshotsDir: path.join(__dirname, baseFolderName),
+ customDiffDir: path.join(__dirname, `${folderName}/`, 'diff'),
+ }),
+});
diff --git a/pages.json b/pages.json
index 11ecc62..489729b 100644
--- a/pages.json
+++ b/pages.json
@@ -631,7 +631,21 @@
"navigationBarTitleText" : "teleport",
"enablePullDownRefresh" : false
}
- }
+ },
+ {
+ "path": "pages/webview-screenshot-comparison/webview-screenshot-comparison",
+ "style": {
+ "navigationBarTitleText": "截图对比测试",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/webview-screenshot/webview-screenshot",
+ "style": {
+ "navigationBarTitleText": "webview 截图测试",
+ "navigationStyle": "custom"
+ }
+ }
],
"tabBar": {
"color": "#7A7E83",
diff --git a/pages/webview-screenshot-comparison/webview-screenshot-comparison.test.js b/pages/webview-screenshot-comparison/webview-screenshot-comparison.test.js
new file mode 100644
index 0000000..6460726
--- /dev/null
+++ b/pages/webview-screenshot-comparison/webview-screenshot-comparison.test.js
@@ -0,0 +1,245 @@
+jest.setTimeout(10000000);
+
+const pages = [
+ 'pages/tab-bar/options-api',
+ 'pages/tab-bar/composition-api',
+ 'pages/app-instance/index/index',
+ 'pages/app-instance/globalProperties/globalProperties',
+ 'pages/built-in-component/keep-alive/keep-alive',
+ 'pages/directive/v-bind/v-bind',
+ 'pages/directive/v-bind/v-bind-class',
+ 'pages/directive/v-bind/v-bind-style',
+ 'pages/directive/v-bind/v-bind-props',
+ 'pages/directive/v-for/v-for',
+ 'pages/directive/v-for/v-for-item-click',
+ 'pages/directive/v-for/v-for-item-v-if',
+ 'pages/directive/v-for/v-for-item-v-show',
+ 'pages/directive/v-for/v-for-v-for',
+ 'pages/directive/v-if/v-if',
+ 'pages/directive/v-model/v-model',
+ 'pages/directive/v-on/v-on',
+ 'pages/directive/v-memo/v-memo',
+ 'pages/directive/v-pre/v-pre',
+ 'pages/directive/v-show/v-show',
+ 'pages/directive/v-slot/v-slot',
+ 'pages/directive/v-html/v-html',
+ 'pages/lifecycle/page/page',
+ 'pages/lifecycle/component/component',
+ 'pages/component-instance/data/data',
+ 'pages/component-instance/props/props',
+ 'pages/component-instance/el/el',
+ 'pages/component-instance/options/options',
+ 'pages/component-instance/slots/slots',
+ 'pages/component-instance/refs/refs',
+ 'pages/component-instance/attrs/attrs',
+ 'pages/component-instance/watch-function/watch-function',
+ 'pages/component-instance/watch-function/watch-array',
+ 'pages/component-instance/emit-function/emit-function',
+
+ 'pages/component-instance/nextTick-function/nextTick-function',
+ 'pages/component-instance/methods/call-method-uni-element',
+
+ 'pages/component-instance/methods/call-method-other',
+ 'pages/component-instance/circular-reference/circular-reference',
+ 'pages/state/data/data',
+ 'pages/state/methods/methods',
+ 'pages/state/props/props',
+ 'pages/state/computed/computed',
+ 'pages/state/watch/watch',
+ 'pages/rendering/slots/slots',
+ 'pages/rendering/template/template',
+ 'pages/rendering/unrecognized-component/unrecognized-component',
+ 'pages/rendering/component/component',
+ 'pages/rendering/render/render',
+
+ 'pages/composition/provide/provide',
+ 'pages/composition/provide/provide-page2',
+ 'pages/composition/inject/inject',
+ 'pages/composition/setup/setup',
+ 'pages/examples/nested-component-communication/nested-component-communication',
+ 'pages/examples/set-custom-child-component-root-node-class/set-custom-child-component-root-node-class',
+ 'pages/composition-api/basic/define-slots/define-slots',
+
+ // 新增
+ 'pages/composition-api/basic/define-emits/define-emits',
+ 'pages/composition-api/basic/define-expose/define-expose',
+
+ 'pages/composition-api/basic/use-attrs/use-attrs',
+ 'pages/composition-api/basic/use-slots/use-slots',
+ 'pages/composition-api/reactivity/ref/ref',
+ 'pages/composition-api/reactivity/computed/computed',
+ 'pages/composition-api/reactivity/reactive/reactive',
+ 'pages/composition-api/reactivity/readonly/readonly',
+ 'pages/composition-api/reactivity/watch/watch',
+ 'pages/composition-api/reactivity/watch-effect/watch-effect',
+ 'pages/composition-api/reactivity/watch-post-effect/watch-post-effect',
+ 'pages/composition-api/reactivity/watch-sync-effect/watch-sync-effect',
+ 'pages/composition-api/reactivity/is-ref/is-ref',
+ 'pages/composition-api/reactivity/un-ref/un-ref',
+ 'pages/composition-api/reactivity/to-ref/to-ref',
+ 'pages/composition-api/reactivity/is-proxy/is-proxy',
+ 'pages/composition-api/reactivity/is-reactive/is-reactive',
+ 'pages/composition-api/reactivity/is-readonly/is-readonly',
+ 'pages/composition-api/reactivity/shallow-ref/shallow-ref',
+ 'pages/composition-api/reactivity/trigger-ref/trigger-ref',
+ 'pages/composition-api/reactivity/custom-ref/custom-ref',
+ 'pages/composition-api/reactivity/shallow-reactive/shallow-reactive',
+ 'pages/composition-api/reactivity/shallow-readonly/shallow-readonly',
+ 'pages/composition-api/reactivity/to-raw/to-raw',
+ 'pages/composition-api/reactivity/mark-raw/mark-raw',
+ 'pages/composition-api/reactivity/effect-scope/effect-scope',
+ 'pages/composition-api/reactivity/get-current-scope/get-current-scope',
+ 'pages/composition-api/reactivity/on-scope-dispose/on-scope-dispose',
+ 'pages/composition-api/lifecycle/page-lifecycle/page-lifecycle',
+ 'pages/composition-api/lifecycle/component-lifecycle/component-lifecycle',
+ 'pages/composition-api/dependency-injection/provide/provide',
+ 'pages/built-in-component/teleport/teleport'
+
+
+ // web暂不支持
+ // 'pages/composition/mixins/mixins',
+ // 'pages/composition/mixins/mixins-page2',
+ // 'pages/directive/v-once/v-once',
+ // 'pages/component-instance/parent/parent',
+ // 'pages/component-instance/root/root',
+ // 'pages/composition-api/basic/define-model/define-model'
+ // 'pages/composition-api/basic/define-options/define-option'
+
+ // 动态内容
+ // 'pages/component-instance/force-update/force-update',
+
+ // 空白页面无内容
+ // 'pages/component-instance/methods/call-method-easycom-uni-modules',
+ // 'pages/component-instance/methods/call-method-easycom',
+
+]
+
+const childToParentPagesMap = new Map([
+
+]);
+
+const customNavigationPages = [
+
+]
+
+const needAdbScreenshotPages = [
+ 'pages/tab-bar/options-api',
+ 'pages/tab-bar/composition-api'
+];
+
+const needAdbScreenshot = (url) => {
+ return needAdbScreenshotPages.includes(url);
+};
+
+const PAGE_PATH =
+ "/pages/webview-screenshot-comparison/webview-screenshot-comparison";
+
+describe("shot-compare", () => {
+ let shouldCompareScreenShot = false
+ if (process.env.uniTestPlatformInfo.startsWith('android')) {
+ let version = process.env.uniTestPlatformInfo
+ version = parseInt(version.split(" ")[1])
+ shouldCompareScreenShot = version > 9
+ }
+
+ if (!shouldCompareScreenShot) {
+ it("other platform not support", async () => {
+ expect(1).toBe(1);
+ });
+ return
+ }
+
+ let page = null;
+ let pageIndex = 0;
+ let baseSrc = "";
+ beforeAll(async () => {
+ page = await program.reLaunch(PAGE_PATH);
+ await page.waitFor(500);
+
+ // set webview-screenshot-comparison page baseSrc
+ baseSrc =
+ process.env.UNI_WEB_SERVICE_URL ? `${process.env.UNI_WEB_SERVICE_URL}/#/` :
+ "http://192.168.31.223:5173/#/";
+ page.setData({
+ baseSrc,
+ });
+ });
+
+ beforeEach(async () => {
+ page = await program.reLaunch(PAGE_PATH);
+ await page.waitFor(500);
+ });
+ afterEach(() => {
+ pageIndex++;
+ });
+
+ test.each(pages)("%s", async () => {
+ const isNeedAdbScreenshot = needAdbScreenshot(pages[pageIndex]);
+ const isCustomNavigationBar = customNavigationPages.includes(pages[pageIndex]);
+ const {
+ statusBarHeight,
+ devicePixelRatio
+ } = await page.data();
+ const screenshotParams = {
+ fullPage: true,
+ adb: isNeedAdbScreenshot,
+ // adb 截图时跳过状态栏
+ area: {
+ x: 0,
+ y: statusBarHeight * devicePixelRatio,
+ },
+ }
+ const screenshotPath = `__webview__${pages[pageIndex].replace(/\//g, "-")}`;
+
+ // web in webview screenshot
+ // 加载依赖页面
+ if (childToParentPagesMap.get(pages[pageIndex])) {
+ await page.setData({
+ src: `${baseSrc}${childToParentPagesMap.get(pages[pageIndex])}`,
+ isLoaded: false
+ });
+ await page.waitFor(async () => {
+ const isLoaded = await page.data("isLoaded");
+ return isLoaded || Date.now() - startTime > 10000;
+ });
+ await page.waitFor(200);
+ }
+ await page.setData({
+ src: `${baseSrc}${pages[pageIndex]}`,
+ isLoaded: false,
+ isCustomNavigationBar,
+ });
+
+ const startTime = Date.now();
+ await page.waitFor(async () => {
+ const isLoaded = await page.data("isLoaded");
+ return isLoaded || Date.now() - startTime > 3000;
+ });
+ await page.waitFor(3000);
+
+ // web 端非 adb 截图时设置 offsetY 移除导航栏
+ const webSnapshot = await program.screenshot({
+ ...screenshotParams,
+ id: 'webview-screenshot-comparison',
+ offsetY: `${isCustomNavigationBar ? 0 : 44}`
+ });
+ expect(webSnapshot).toMatchImageSnapshot({
+ customSnapshotIdentifier() {
+ return screenshotPath;
+ },
+ });
+
+ // app-android page screenshot comparison
+ const navigateMethod = pages[pageIndex].startsWith("pages/tab-bar") ?
+ "switchTab" :
+ "navigateTo";
+ page = await program[navigateMethod](`/${pages[pageIndex]}`);
+ await page.waitFor(500);
+ const appAndroidSnapshot = await program.screenshot(screenshotParams);
+ expect(appAndroidSnapshot).toMatchImageSnapshot({
+ customSnapshotIdentifier() {
+ return screenshotPath;
+ },
+ });
+ });
+});
diff --git a/pages/webview-screenshot-comparison/webview-screenshot-comparison.uvue b/pages/webview-screenshot-comparison/webview-screenshot-comparison.uvue
new file mode 100644
index 0000000..450215e
--- /dev/null
+++ b/pages/webview-screenshot-comparison/webview-screenshot-comparison.uvue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/webview-screenshot/webview-screenshot.test.js b/pages/webview-screenshot/webview-screenshot.test.js
new file mode 100644
index 0000000..50265ba
--- /dev/null
+++ b/pages/webview-screenshot/webview-screenshot.test.js
@@ -0,0 +1,228 @@
+jest.setTimeout(10000000);
+
+const pages = [
+ 'pages/tab-bar/options-api',
+ 'pages/tab-bar/composition-api',
+ 'pages/app-instance/index/index',
+ 'pages/app-instance/globalProperties/globalProperties',
+ 'pages/built-in-component/keep-alive/keep-alive',
+ 'pages/directive/v-bind/v-bind',
+ 'pages/directive/v-bind/v-bind-class',
+ 'pages/directive/v-bind/v-bind-style',
+ 'pages/directive/v-bind/v-bind-props',
+ 'pages/directive/v-for/v-for',
+ 'pages/directive/v-for/v-for-item-click',
+ 'pages/directive/v-for/v-for-item-v-if',
+ 'pages/directive/v-for/v-for-item-v-show',
+ 'pages/directive/v-for/v-for-v-for',
+ 'pages/directive/v-if/v-if',
+ 'pages/directive/v-model/v-model',
+ 'pages/directive/v-on/v-on',
+ 'pages/directive/v-memo/v-memo',
+ 'pages/directive/v-pre/v-pre',
+ 'pages/directive/v-show/v-show',
+ 'pages/directive/v-slot/v-slot',
+ 'pages/directive/v-html/v-html',
+ 'pages/lifecycle/page/page',
+ 'pages/lifecycle/component/component',
+ 'pages/component-instance/data/data',
+ 'pages/component-instance/props/props',
+ 'pages/component-instance/el/el',
+ 'pages/component-instance/options/options',
+ 'pages/component-instance/slots/slots',
+ 'pages/component-instance/refs/refs',
+ 'pages/component-instance/attrs/attrs',
+ 'pages/component-instance/watch-function/watch-function',
+ 'pages/component-instance/watch-function/watch-array',
+ 'pages/component-instance/emit-function/emit-function',
+
+ 'pages/component-instance/nextTick-function/nextTick-function',
+ 'pages/component-instance/methods/call-method-uni-element',
+
+ 'pages/component-instance/methods/call-method-other',
+ 'pages/component-instance/circular-reference/circular-reference',
+ 'pages/state/data/data',
+ 'pages/state/methods/methods',
+ 'pages/state/props/props',
+ 'pages/state/computed/computed',
+ 'pages/state/watch/watch',
+ 'pages/rendering/slots/slots',
+ 'pages/rendering/template/template',
+ 'pages/rendering/unrecognized-component/unrecognized-component',
+ 'pages/rendering/component/component',
+ 'pages/rendering/render/render',
+
+ 'pages/composition/provide/provide',
+ 'pages/composition/provide/provide-page2',
+ 'pages/composition/inject/inject',
+ 'pages/composition/setup/setup',
+ 'pages/examples/nested-component-communication/nested-component-communication',
+ 'pages/examples/set-custom-child-component-root-node-class/set-custom-child-component-root-node-class',
+ 'pages/composition-api/basic/define-slots/define-slots',
+
+ // 新增
+ 'pages/composition-api/basic/define-emits/define-emits',
+ 'pages/composition-api/basic/define-expose/define-expose',
+
+ 'pages/composition-api/basic/use-attrs/use-attrs',
+ 'pages/composition-api/basic/use-slots/use-slots',
+ 'pages/composition-api/reactivity/ref/ref',
+ 'pages/composition-api/reactivity/computed/computed',
+ 'pages/composition-api/reactivity/reactive/reactive',
+ 'pages/composition-api/reactivity/readonly/readonly',
+ 'pages/composition-api/reactivity/watch/watch',
+ 'pages/composition-api/reactivity/watch-effect/watch-effect',
+ 'pages/composition-api/reactivity/watch-post-effect/watch-post-effect',
+ 'pages/composition-api/reactivity/watch-sync-effect/watch-sync-effect',
+ 'pages/composition-api/reactivity/is-ref/is-ref',
+ 'pages/composition-api/reactivity/un-ref/un-ref',
+ 'pages/composition-api/reactivity/to-ref/to-ref',
+ 'pages/composition-api/reactivity/is-proxy/is-proxy',
+ 'pages/composition-api/reactivity/is-reactive/is-reactive',
+ 'pages/composition-api/reactivity/is-readonly/is-readonly',
+ 'pages/composition-api/reactivity/shallow-ref/shallow-ref',
+ 'pages/composition-api/reactivity/trigger-ref/trigger-ref',
+ 'pages/composition-api/reactivity/custom-ref/custom-ref',
+ 'pages/composition-api/reactivity/shallow-reactive/shallow-reactive',
+ 'pages/composition-api/reactivity/shallow-readonly/shallow-readonly',
+ 'pages/composition-api/reactivity/to-raw/to-raw',
+ 'pages/composition-api/reactivity/mark-raw/mark-raw',
+ 'pages/composition-api/reactivity/effect-scope/effect-scope',
+ 'pages/composition-api/reactivity/get-current-scope/get-current-scope',
+ 'pages/composition-api/reactivity/on-scope-dispose/on-scope-dispose',
+ 'pages/composition-api/lifecycle/page-lifecycle/page-lifecycle',
+ 'pages/composition-api/lifecycle/component-lifecycle/component-lifecycle',
+ 'pages/composition-api/dependency-injection/provide/provide',
+ 'pages/built-in-component/teleport/teleport'
+
+
+ // web暂不支持
+ // 'pages/composition/mixins/mixins',
+ // 'pages/composition/mixins/mixins-page2',
+ // 'pages/directive/v-once/v-once',
+ // 'pages/component-instance/parent/parent',
+ // 'pages/component-instance/root/root',
+ // 'pages/composition-api/basic/define-model/define-model'
+ // 'pages/composition-api/basic/define-options/define-option'
+
+ // 动态内容
+ // 'pages/component-instance/force-update/force-update',
+
+ // 空白页面无内容
+ // 'pages/component-instance/methods/call-method-easycom-uni-modules',
+ // 'pages/component-instance/methods/call-method-easycom',
+
+]
+
+const childToParentPagesMap = new Map([]);
+
+const customNavigationPages = [
+
+]
+
+const needAdbScreenshotPages = [
+ 'pages/tab-bar/options-api',
+ 'pages/tab-bar/composition-api',
+];
+
+const needAdbScreenshot = (url) => {
+ return needAdbScreenshotPages.includes(url);
+};
+
+const PAGE_PATH =
+ "/pages/webview-screenshot/webview-screenshot";
+
+describe("shot-compare", () => {
+ let shouldCompareScreenShot = false
+ if (process.env.uniTestPlatformInfo.startsWith('android')) {
+ let version = process.env.uniTestPlatformInfo
+ version = parseInt(version.split(" ")[1])
+ shouldCompareScreenShot = version > 9
+ }
+
+ if (!shouldCompareScreenShot) {
+ it("other platform not support", async () => {
+ expect(1).toBe(1);
+ });
+ return
+ }
+ let page = null;
+ let pageIndex = 0;
+ let baseSrc = "";
+ beforeAll(async () => {
+ page = await program.reLaunch(PAGE_PATH);
+ await page.waitFor(500);
+
+ // set webview-screenshot page baseSrc
+ baseSrc =
+ process.env.UNI_WEB_SERVICE_URL ? `${process.env.UNI_WEB_SERVICE_URL}/#/` :
+ "http://192.168.31.223:5173/#/";
+ page.setData({
+ baseSrc,
+ });
+ });
+
+ beforeEach(async () => {
+ page = await program.reLaunch(PAGE_PATH);
+ await page.waitFor(500);
+ });
+ afterEach(() => {
+ pageIndex++;
+ });
+
+ test.each(pages)("%s", async () => {
+ const isNeedAdbScreenshot = needAdbScreenshot(pages[pageIndex]);
+ const isCustomNavigation = customNavigationPages.includes(pages[pageIndex]);
+ const {
+ headerHeight,
+ devicePixelRatio
+ } = await page.data();
+ const screenshotParams = {
+ fullPage: true,
+ adb: isNeedAdbScreenshot,
+ // adb 截图时跳过状态栏
+ area: {
+ x: 0,
+ y: headerHeight * devicePixelRatio,
+ },
+ }
+ const screenshotPath = `webview-shot__${pages[pageIndex].replace(/\//g, "-")}`;
+
+ // web in webview screenshot
+ // 加载依赖页面
+ if (childToParentPagesMap.get(pages[pageIndex])) {
+ await page.setData({
+ src: `${baseSrc}${childToParentPagesMap.get(pages[pageIndex])}`,
+ isLoaded: false
+ });
+ await page.waitFor(async () => {
+ const isLoaded = await page.data("isLoaded");
+ return isLoaded || Date.now() - startTime > 10000;
+ });
+ await page.waitFor(200);
+ }
+ await page.setData({
+ src: `${baseSrc}${pages[pageIndex]}`,
+ isLoaded: false,
+ needRemoveWebHead: !isNeedAdbScreenshot
+ });
+
+ const startTime = Date.now();
+ await page.waitFor(async () => {
+ const isLoaded = await page.data("isLoaded");
+ return isLoaded || Date.now() - startTime > 3000;
+ });
+ await page.waitFor(4000);
+
+ // web 端非 adb 截图时设置 offsetY 移除导航栏
+ const webSnapshot = await program.screenshot({
+ ...screenshotParams,
+ offsetY: `${isCustomNavigation ? 0 : headerHeight}`
+ });
+ expect(webSnapshot).toMatchImageSnapshot({
+ customSnapshotIdentifier() {
+ return screenshotPath;
+ },
+ });
+ });
+});
\ No newline at end of file
diff --git a/pages/webview-screenshot/webview-screenshot.uvue b/pages/webview-screenshot/webview-screenshot.uvue
new file mode 100644
index 0000000..8fe984c
--- /dev/null
+++ b/pages/webview-screenshot/webview-screenshot.uvue
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
--
GitLab