@react-native-windows/automation-commands 0.0.0-canary.1016

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # @react-native-windows/automation-commands
2
+
3
+ `@react-native-windows/automation-commands` provides built-in commands that may
4
+ be used with `@react-native-windows/automation-channel` to make it easier to
5
+ test your application.
6
+
7
+ **This package is a work in progress**
8
+
9
+ ## Adding to your application
10
+
11
+ **TBD**
12
+
13
+ ## Commands
14
+
15
+ ### dumpVisualTree
16
+
17
+ The `dumpVisualTree` command creates a JSON object corresponding to the XAML
18
+ tree under a given testID. This can be used in conjunction with snapshot
19
+ testing to validate that your native UI looks how you could expect.
20
+
21
+ ```ts
22
+ import {dumpVisualTree} from '@react-native-windows/automation-commands';
23
+
24
+ test('Widget', async () => {
25
+ const dump = await dumpVisualTree('widget-test-id');
26
+ expect(dump).toMatchSnapshot();
27
+ });
28
+ ```
29
+
30
+ #### Options
31
+ **TBD**
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ * Licensed under the MIT License.
4
+ *
5
+ * @format
6
+ */
7
+ import { AutomationClient } from '@react-native-windows/automation-channel';
8
+ /**
9
+ * Schema of tree dumped node
10
+ */
11
+ export type UIElement = {
12
+ XamlType: string;
13
+ Foreground?: string | null;
14
+ Background?: string | null;
15
+ Padding?: string | null;
16
+ Margin?: string | null;
17
+ RenderSize?: number[] | null;
18
+ Visibility?: 'Collapsed' | 'Visible' | null;
19
+ CornerRadius?: string | null;
20
+ BorderThickness?: string | null;
21
+ Width?: number | null;
22
+ Height?: number | null;
23
+ BorderBrush?: string | null;
24
+ VerticalAlignment?: string | null;
25
+ HorizontalAlignment?: string | null;
26
+ Clip?: string | null;
27
+ FlowDirection?: string | null;
28
+ Name?: string | null;
29
+ Text?: string | null;
30
+ children?: UIElement[];
31
+ [index: string]: unknown;
32
+ };
33
+ export type AutomationNode = {
34
+ AutomationId?: string;
35
+ ControlType?: number;
36
+ LocalizedControlType?: string;
37
+ __Children?: [AutomationNode];
38
+ };
39
+ export type ComponentNode = {
40
+ Type: string;
41
+ _Props?: {
42
+ TestId?: string;
43
+ Sources?: [{
44
+ Uri?: string;
45
+ }];
46
+ };
47
+ __Children?: [ComponentNode];
48
+ };
49
+ export type VisualNode = {
50
+ Comment?: string;
51
+ Offset?: `${number} ${number} ${number}`;
52
+ Size?: `${number} ${number}`;
53
+ 'Visual Type'?: string;
54
+ __Children?: [VisualNode];
55
+ };
56
+ export type VisualTree = {
57
+ 'Automation Tree': AutomationNode;
58
+ 'Component Tree': ComponentNode;
59
+ 'Visual Tree': VisualNode;
60
+ };
61
+ declare global {
62
+ const automationClient: AutomationClient | undefined;
63
+ }
64
+ /**
65
+ * Dump a section of the native visual tree.
66
+ */
67
+ export default function dumpVisualTree(accessibilityId: string, opts?: {
68
+ pruneCollapsed?: boolean;
69
+ deterministicOnly?: boolean;
70
+ removeDefaultProps?: boolean;
71
+ removeGuidsFromImageSources?: boolean;
72
+ additionalProperties?: string[];
73
+ }): Promise<UIElement | VisualTree>;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ * Licensed under the MIT License.
5
+ *
6
+ * @format
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ /**
10
+ * Dump a section of the native visual tree.
11
+ */
12
+ async function dumpVisualTree(accessibilityId, opts) {
13
+ if (!automationClient) {
14
+ throw new Error('RPC client is not enabled');
15
+ }
16
+ const dumpResponse = await automationClient.invoke('DumpVisualTree', {
17
+ accessibilityId,
18
+ ...opts,
19
+ });
20
+ if (dumpResponse.type === 'error') {
21
+ throw new Error(dumpResponse.message);
22
+ }
23
+ const element = dumpResponse.result;
24
+ if ('XamlType' in element && (opts === null || opts === void 0 ? void 0 : opts.pruneCollapsed) !== false) {
25
+ pruneCollapsedElements(element);
26
+ }
27
+ if ('XamlType' in element && (opts === null || opts === void 0 ? void 0 : opts.deterministicOnly) !== false) {
28
+ removeNonDeterministicProps(element);
29
+ }
30
+ if ('XamlType' in element && (opts === null || opts === void 0 ? void 0 : opts.removeDefaultProps) !== false) {
31
+ removeDefaultProps(element);
32
+ }
33
+ if (!('XamlType' in element) && (opts === null || opts === void 0 ? void 0 : opts.removeGuidsFromImageSources) !== false) {
34
+ removeGuidsFromImageSources(element);
35
+ }
36
+ return element;
37
+ }
38
+ exports.default = dumpVisualTree;
39
+ function removeGuidsFromImageSourcesHelper(node) {
40
+ if (node._Props && node._Props.Sources) {
41
+ node._Props.Sources.forEach((source) => {
42
+ if (source.Uri) {
43
+ if (source.Uri.startsWith('blob:')) {
44
+ source.Uri = source.Uri.replace(/blob:[a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+/, 'blob:<some_guid_here>');
45
+ source.Uri = source.Uri.replace(/size=\d{5}/, 'size=<size>');
46
+ }
47
+ else if (source.Uri.startsWith('https://www.facebook.com/assets/fb_lite_messaging/E2EE-settings@3x.png?r=1&t=')) {
48
+ source.Uri =
49
+ 'https://www.facebook.com/assets/fb_lite_messaging/E2EE-settings@3x.png?r=1&t=<some_hash_here>';
50
+ }
51
+ else if (source.Uri.startsWith('https://www.facebook.com/ar_effect/external_textures/648609739826677.png?hash=')) {
52
+ source.Uri =
53
+ 'https://www.facebook.com/ar_effect/external_textures/648609739826677.png?hash=<some_hash_here>';
54
+ }
55
+ else if (source.Uri.startsWith('https://www.facebook.com/ads/pics/successstories.png?hash=')) {
56
+ source.Uri =
57
+ 'https://www.facebook.com/ads/pics/successstories.png?hash=<some_hash_here>';
58
+ }
59
+ else {
60
+ // When getting files from a prebuilt bundle the uri is going to include a local path, which would make snapshots inconsistent,
61
+ // This logic replaces the local path so that we get consistent results.
62
+ // file://E:\\repos\\react-native-windows\\packages\\e2e-test-app-fabric\\windows\\RNTesterApp-Fabric.Package\\bin\\x64\\Release\\AppX\\RNTesterApp-Fabric\\Bundle\\@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png
63
+ // becomes
64
+ // <localOrBundlerUri>@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png
65
+ const packagesPath = require('path')
66
+ .resolve(__dirname, '../../..')
67
+ .replace(/\\/g, '\\\\');
68
+ source.Uri = source.Uri.replace(new RegExp(`file://${packagesPath}.*\\\\Bundle\\\\assets/_+`), '<localOrBundlerUri>');
69
+ // When loading the bundle from metro local paths will be replaced with paths to localhost, which will not align with snapshots made with prebuilt bundles.
70
+ // This logic replaces the localhost uri, with the same uri that we would have gotten from a prebuild bundle. This makes it easier to debug without breaking snapshots
71
+ // http://localhost:8081/assets/@@/@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png?platform=windows&hash=c6f5aec4d9e0aa47c0887e4266796224
72
+ // becomes
73
+ // "<localOrBundlerUri>@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png"
74
+ source.Uri = source.Uri.replace(/http:\/\/localhost:8081\/assets\/(@@\/)+/, '<localOrBundlerUri>');
75
+ source.Uri = source.Uri.replace(/\?platform=windows&hash=[^=]$/, '');
76
+ }
77
+ }
78
+ });
79
+ }
80
+ if (node.__Children) {
81
+ node.__Children.forEach((child) => removeGuidsFromImageSourcesHelper(child));
82
+ }
83
+ }
84
+ function removeGuidsFromImageSources(visualTree) {
85
+ removeGuidsFromImageSourcesHelper(visualTree['Component Tree']);
86
+ }
87
+ /**
88
+ * Removes trees of XAML that are not visible.
89
+ */
90
+ function pruneCollapsedElements(element) {
91
+ if (!element.children) {
92
+ return;
93
+ }
94
+ element.children = element.children.filter(child => child.Visibility !== 'Collapsed');
95
+ element.children.forEach(pruneCollapsedElements);
96
+ }
97
+ /**
98
+ * Removes trees of properties that are not deterministic
99
+ */
100
+ function removeNonDeterministicProps(element) {
101
+ if (element.RenderSize) {
102
+ // RenderSize is subject to rounding, etc and should mostly be derived from
103
+ // other deterministic properties in the tree.
104
+ delete element.RenderSize;
105
+ }
106
+ if (element.children) {
107
+ element.children.forEach(removeNonDeterministicProps);
108
+ }
109
+ }
110
+ /**
111
+ * Removes noise from snapshot by removing properties with the default value
112
+ */
113
+ function removeDefaultProps(element) {
114
+ const defaultValues = [['Tooltip', null]];
115
+ defaultValues.forEach(([propname, defaultValue]) => {
116
+ if (element[propname] === defaultValue) {
117
+ delete element[propname];
118
+ }
119
+ });
120
+ if (element.children) {
121
+ element.children.forEach(removeDefaultProps);
122
+ }
123
+ }
124
+ //# sourceMappingURL=dumpVisualTree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dumpVisualTree.js","sourceRoot":"","sources":["../src/dumpVisualTree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright (c) Microsoft Corporation.\n * Licensed under the MIT License.\n *\n * @format\n */\n\nimport {AutomationClient} from '@react-native-windows/automation-channel';\n\n/**\n * Schema of tree dumped node\n */\nexport type UIElement = {\n XamlType: string;\n Foreground?: string | null;\n Background?: string | null;\n Padding?: string | null;\n Margin?: string | null;\n RenderSize?: number[] | null;\n Visibility?: 'Collapsed' | 'Visible' | null;\n CornerRadius?: string | null;\n BorderThickness?: string | null;\n Width?: number | null;\n Height?: number | null;\n BorderBrush?: string | null;\n VerticalAlignment?: string | null;\n HorizontalAlignment?: string | null;\n Clip?: string | null;\n FlowDirection?: string | null;\n Name?: string | null;\n Text?: string | null;\n children?: UIElement[];\n [index: string]: unknown;\n};\n\nexport type AutomationNode = {\n AutomationId?: string;\n ControlType?: number;\n LocalizedControlType?: string;\n __Children?: [AutomationNode];\n};\n\nexport type ComponentNode = {\n Type: string;\n _Props?: {\n TestId?: string;\n Sources?: [{Uri?: string}];\n };\n __Children?: [ComponentNode];\n};\n\nexport type VisualNode = {\n Comment?: string;\n Offset?: `${number} ${number} ${number}`;\n Size?: `${number} ${number}`;\n 'Visual Type'?: string;\n __Children?: [VisualNode];\n};\n\nexport type VisualTree = {\n 'Automation Tree': AutomationNode;\n 'Component Tree': ComponentNode;\n 'Visual Tree': VisualNode;\n};\n\ndeclare global {\n const automationClient: AutomationClient | undefined;\n}\n\n/**\n * Dump a section of the native visual tree.\n */\nexport default async function dumpVisualTree(\n accessibilityId: string,\n opts?: {\n pruneCollapsed?: boolean;\n deterministicOnly?: boolean;\n removeDefaultProps?: boolean;\n removeGuidsFromImageSources?: boolean;\n additionalProperties?: string[];\n },\n): Promise<UIElement | VisualTree> {\n if (!automationClient) {\n throw new Error('RPC client is not enabled');\n }\n\n const dumpResponse = await automationClient.invoke('DumpVisualTree', {\n accessibilityId,\n ...opts,\n });\n\n if (dumpResponse.type === 'error') {\n throw new Error(dumpResponse.message);\n }\n\n const element: UIElement | VisualTree = dumpResponse.result;\n\n if ('XamlType' in element && opts?.pruneCollapsed !== false) {\n pruneCollapsedElements(element);\n }\n\n if ('XamlType' in element && opts?.deterministicOnly !== false) {\n removeNonDeterministicProps(element);\n }\n\n if ('XamlType' in element && opts?.removeDefaultProps !== false) {\n removeDefaultProps(element);\n }\n\n if (!('XamlType' in element) && opts?.removeGuidsFromImageSources !== false) {\n removeGuidsFromImageSources(element);\n }\n\n return element;\n}\n\nfunction removeGuidsFromImageSourcesHelper(node: ComponentNode) {\n if (node._Props && node._Props.Sources) {\n node._Props.Sources.forEach((source: any) => {\n if (source.Uri) {\n if (source.Uri.startsWith('blob:')) {\n source.Uri = source.Uri.replace(\n /blob:[a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+-[a-f0-9]+/,\n 'blob:<some_guid_here>',\n );\n source.Uri = source.Uri.replace(/size=\\d{5}/, 'size=<size>');\n } else if (\n source.Uri.startsWith(\n 'https://www.facebook.com/assets/fb_lite_messaging/E2EE-settings@3x.png?r=1&t=',\n )\n ) {\n source.Uri =\n 'https://www.facebook.com/assets/fb_lite_messaging/E2EE-settings@3x.png?r=1&t=<some_hash_here>';\n } else if (\n source.Uri.startsWith(\n 'https://www.facebook.com/ar_effect/external_textures/648609739826677.png?hash=',\n )\n ) {\n source.Uri =\n 'https://www.facebook.com/ar_effect/external_textures/648609739826677.png?hash=<some_hash_here>';\n } else if (\n source.Uri.startsWith(\n 'https://www.facebook.com/ads/pics/successstories.png?hash=',\n )\n ) {\n source.Uri =\n 'https://www.facebook.com/ads/pics/successstories.png?hash=<some_hash_here>';\n } else {\n // When getting files from a prebuilt bundle the uri is going to include a local path, which would make snapshots inconsistent,\n // This logic replaces the local path so that we get consistent results.\n // file://E:\\\\repos\\\\react-native-windows\\\\packages\\\\e2e-test-app-fabric\\\\windows\\\\RNTesterApp-Fabric.Package\\\\bin\\\\x64\\\\Release\\\\AppX\\\\RNTesterApp-Fabric\\\\Bundle\\\\@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png\n // becomes\n // <localOrBundlerUri>@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png\n const packagesPath = require('path')\n .resolve(__dirname, '../../..')\n .replace(/\\\\/g, '\\\\\\\\');\n source.Uri = source.Uri.replace(\n new RegExp(`file://${packagesPath}.*\\\\\\\\Bundle\\\\\\\\assets/_+`),\n '<localOrBundlerUri>',\n );\n\n // When loading the bundle from metro local paths will be replaced with paths to localhost, which will not align with snapshots made with prebuilt bundles.\n // This logic replaces the localhost uri, with the same uri that we would have gotten from a prebuild bundle. This makes it easier to debug without breaking snapshots\n // http://localhost:8081/assets/@@/@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png?platform=windows&hash=c6f5aec4d9e0aa47c0887e4266796224\n // becomes\n // \"<localOrBundlerUri>@react-native-windows/tester/js/assets/uie_thumb_normal@2x.png\"\n source.Uri = source.Uri.replace(\n /http:\\/\\/localhost:8081\\/assets\\/(@@\\/)+/,\n '<localOrBundlerUri>',\n );\n source.Uri = source.Uri.replace(/\\?platform=windows&hash=[^=]$/, '');\n }\n }\n });\n }\n if (node.__Children) {\n node.__Children.forEach((child: any) =>\n removeGuidsFromImageSourcesHelper(child),\n );\n }\n}\n\nfunction removeGuidsFromImageSources(visualTree: VisualTree) {\n removeGuidsFromImageSourcesHelper(visualTree['Component Tree']);\n}\n\n/**\n * Removes trees of XAML that are not visible.\n */\nfunction pruneCollapsedElements(element: UIElement) {\n if (!element.children) {\n return;\n }\n\n element.children = element.children.filter(\n child => child.Visibility !== 'Collapsed',\n );\n\n element.children.forEach(pruneCollapsedElements);\n}\n\n/**\n * Removes trees of properties that are not deterministic\n */\nfunction removeNonDeterministicProps(element: UIElement) {\n if (element.RenderSize) {\n // RenderSize is subject to rounding, etc and should mostly be derived from\n // other deterministic properties in the tree.\n delete element.RenderSize;\n }\n\n if (element.children) {\n element.children.forEach(removeNonDeterministicProps);\n }\n}\n\n/**\n * Removes noise from snapshot by removing properties with the default value\n */\nfunction removeDefaultProps(element: UIElement) {\n const defaultValues: [string, unknown][] = [['Tooltip', null]];\n\n defaultValues.forEach(([propname, defaultValue]) => {\n if (element[propname] === defaultValue) {\n delete element[propname];\n }\n });\n\n if (element.children) {\n element.children.forEach(removeDefaultProps);\n }\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation.
3
+ * Licensed under the MIT License.
4
+ *
5
+ * @format
6
+ */
7
+ import dumpVisualTree from './dumpVisualTree';
8
+ export { dumpVisualTree };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Microsoft Corporation.
4
+ * Licensed under the MIT License.
5
+ *
6
+ * @format
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.dumpVisualTree = void 0;
13
+ const dumpVisualTree_1 = __importDefault(require("./dumpVisualTree"));
14
+ exports.dumpVisualTree = dumpVisualTree_1.default;
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,sEAA8C;AAEtC,yBAFD,wBAAc,CAEC","sourcesContent":["/**\n * Copyright (c) Microsoft Corporation.\n * Licensed under the MIT License.\n *\n * @format\n */\n\nimport dumpVisualTree from './dumpVisualTree';\n\nexport {dumpVisualTree};\n"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@react-native-windows/automation-commands",
3
+ "version": "0.0.0-canary.1016",
4
+ "description": "Allows controlling your react-native-windows application",
5
+ "main": "lib-commonjs/index.js",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/microsoft/react-native-windows",
10
+ "directory": "packages/@react-native-windows/automation-commands"
11
+ },
12
+ "private": false,
13
+ "scripts": {
14
+ "build": "rnw-scripts build",
15
+ "clean": "rnw-scripts clean",
16
+ "lint": "rnw-scripts lint",
17
+ "lint:fix": "rnw-scripts lint:fix",
18
+ "watch": "rnw-scripts watch"
19
+ },
20
+ "dependencies": {
21
+ "@react-native-windows/automation-channel": "0.0.0-canary.1016",
22
+ "@typescript-eslint/eslint-plugin": "^7.1.1",
23
+ "@typescript-eslint/parser": "^7.1.1"
24
+ },
25
+ "devDependencies": {
26
+ "@jest/types": "^29.2.1",
27
+ "@rnw-scripts/eslint-config": "1.2.38",
28
+ "@rnw-scripts/just-task": "2.3.58",
29
+ "@rnw-scripts/ts-config": "2.0.6",
30
+ "@types/jest": "^29.2.2",
31
+ "@types/node": "^22.14.0",
32
+ "eslint": "^8.19.0",
33
+ "prettier": "2.8.8",
34
+ "typescript": "5.0.4"
35
+ },
36
+ "files": [
37
+ "lib-commonjs",
38
+ "README.md"
39
+ ],
40
+ "beachball": {
41
+ "defaultNpmTag": "canary",
42
+ "disallowedChangeTypes": [
43
+ "major",
44
+ "minor",
45
+ "patch",
46
+ "premajor",
47
+ "preminor",
48
+ "prepatch"
49
+ ]
50
+ },
51
+ "promoteRelease": true,
52
+ "engines": {
53
+ "node": ">= 22"
54
+ }
55
+ }