chore(ng-schematics): Add Angular Schematics (#9222)

**What kind of change does this PR introduce?**

It introduces schematic for Angular that integrate with its CLI.
First revision support Jasmine.

**Did you add tests for your changes?**

Added Unit tests for each scenario. 

**Summary**

The idea is to provide a an example for setting up Puppeteer and Angular
for testing user flows.

**Does this PR introduce a breaking change?**

No

**Other information**

For Feature PRs:

- Introduce CL for tests
- Hook up NPM package publishing
- Update README.md
This commit is contained in:
Nikolay Vitkov 2022-11-09 14:52:10 +01:00 committed by GitHub
parent 8c211d6ae4
commit 3f2c0590f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 2446 additions and 42 deletions

521
package-lock.json generated
View File

@ -80,6 +80,110 @@
"zod": "3.19.1"
}
},
"node_modules/@angular-devkit/core": {
"version": "14.2.7",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.7.tgz",
"integrity": "sha512-83SCYP3h6fglWMgAXFDc8HfOxk9t3ugK0onATXchctvA7blW4Vx8BSg3/DgbqCv+fF380SN8bYqqLJl8fQFdzg==",
"dependencies": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
},
"engines": {
"node": "^14.15.0 || >=16.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^3.5.2"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular-devkit/core/node_modules/jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg=="
},
"node_modules/@angular-devkit/core/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"engines": {
"node": ">= 8"
}
},
"node_modules/@angular-devkit/schematics": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.8.tgz",
"integrity": "sha512-L5GEgueZV4vqZy9Ar0zxVJOHK/4ttF1nPjW4Ut1vRFJGxsHFVEpxq5eGBf2JYSiOhqmFYc6GnJOxA6C4xAIHjA==",
"dependencies": {
"@angular-devkit/core": "14.2.8",
"jsonc-parser": "3.1.0",
"magic-string": "0.26.2",
"ora": "5.4.1",
"rxjs": "6.6.7"
},
"engines": {
"node": "^14.15.0 || >=16.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.8.tgz",
"integrity": "sha512-30nDq2PH91X7T42xXFBlTiXTBG143z0BL8IUgpVCxTFYwxgPbtV4bcXTkiBgh1FL/usZcHa0Bd/64wxmFOpYwA==",
"dependencies": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
},
"engines": {
"node": "^14.15.0 || >=16.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^3.5.2"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg=="
},
"node_modules/@angular-devkit/schematics/node_modules/magic-string": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz",
"integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==",
"dependencies": {
"sourcemap-codec": "^1.4.8"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@angular-devkit/schematics/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"engines": {
"node": ">= 8"
}
},
"node_modules/@babel/code-frame": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
@ -1636,6 +1740,10 @@
"resolved": "test",
"link": true
},
"node_modules/@puppeteer/ng-schematics": {
"resolved": "packages/ng-schematics",
"link": true
},
"node_modules/@rushstack/node-core-library": {
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.52.0.tgz",
@ -1712,6 +1820,63 @@
"string-argv": "~0.3.1"
}
},
"node_modules/@schematics/angular": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.8.tgz",
"integrity": "sha512-SuzeCpWHF9+8jey7WheM1Va0iyJrYAD88O2VT2x0NEF2PXEH63lV7BCBtE7kKurIAmXBbvTCsPyZuFKYJGDHFA==",
"dev": true,
"dependencies": {
"@angular-devkit/core": "14.2.8",
"@angular-devkit/schematics": "14.2.8",
"jsonc-parser": "3.1.0"
},
"engines": {
"node": "^14.15.0 || >=16.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@schematics/angular/node_modules/@angular-devkit/core": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.8.tgz",
"integrity": "sha512-30nDq2PH91X7T42xXFBlTiXTBG143z0BL8IUgpVCxTFYwxgPbtV4bcXTkiBgh1FL/usZcHa0Bd/64wxmFOpYwA==",
"dev": true,
"dependencies": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
},
"engines": {
"node": "^14.15.0 || >=16.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^3.5.2"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@schematics/angular/node_modules/jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==",
"dev": true
},
"node_modules/@schematics/angular/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true,
"engines": {
"node": ">= 8"
}
},
"node_modules/@sinonjs/commons": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
@ -2294,7 +2459,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
"dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@ -2306,6 +2470,22 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@ -2736,7 +2916,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"dev": true,
"dependencies": {
"restore-cursor": "^3.1.0"
},
@ -2744,6 +2923,17 @@
"node": ">=8"
}
},
"node_modules/cli-spinners": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
"integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==",
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
@ -2767,6 +2957,14 @@
"node": ">=12"
}
},
"node_modules/clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
"engines": {
"node": ">=0.8"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -3024,6 +3222,17 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"node_modules/defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
"integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"dependencies": {
"clone": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/define-properties": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
@ -4302,8 +4511,7 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-diff": {
"version": "1.2.0",
@ -5202,6 +5410,14 @@
"node": ">=0.10.0"
}
},
"node_modules/is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
"engines": {
"node": ">=8"
}
},
"node_modules/is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@ -5570,8 +5786,7 @@
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@ -5909,7 +6124,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -6470,7 +6684,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"dependencies": {
"mimic-fn": "^2.1.0"
},
@ -6498,6 +6711,28 @@
"node": ">= 0.8.0"
}
},
"node_modules/ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
"integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
"dependencies": {
"bl": "^4.1.0",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-spinners": "^2.5.0",
"is-interactive": "^1.0.0",
"is-unicode-supported": "^0.1.0",
"log-symbols": "^4.1.0",
"strip-ansi": "^6.0.0",
"wcwidth": "^1.0.1"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@ -6781,7 +7016,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -7113,7 +7347,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -7155,7 +7388,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"dev": true,
"dependencies": {
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
@ -7328,7 +7560,6 @@
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"dependencies": {
"tslib": "^1.9.0"
},
@ -7445,8 +7676,7 @@
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/sinon": {
"version": "14.0.0",
@ -7497,8 +7727,7 @@
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"node_modules/spdx-correct": {
"version": "3.1.1",
@ -7994,8 +8223,7 @@
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/tsutils": {
"version": "3.21.0",
@ -8112,7 +8340,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
@ -8171,6 +8398,14 @@
"node": ">= 0.10"
}
},
"node_modules/wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
"integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
"dependencies": {
"defaults": "^1.0.3"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@ -8463,6 +8698,28 @@
"url": "https://github.com/sponsors/colinhacks"
}
},
"packages/ng-schematics": {
"name": "@puppeteer/ng-schematics",
"version": "0.0.0",
"license": "Apache-2.0",
"dependencies": {
"@angular-devkit/core": "^14.2.6",
"@angular-devkit/schematics": "^14.2.6"
},
"devDependencies": {
"@schematics/angular": "^14.2.8",
"@types/node": "^14.15.0"
},
"engines": {
"node": ">=14.1.0"
}
},
"packages/ng-schematics/node_modules/@types/node": {
"version": "14.18.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz",
"integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==",
"dev": true
},
"packages/puppeteer": {
"version": "19.2.2",
"hasInstallScript": true,
@ -8498,6 +8755,24 @@
"node": ">=14.1.0"
}
},
"packages/puppeteer-schematics": {
"version": "0.0.0",
"extraneous": true,
"license": "Apache-2.0",
"dependencies": {
"@angular-devkit/architect": "0.1402.7",
"@angular-devkit/core": "^14.2.6",
"@angular-devkit/schematics": "^14.2.6",
"@schematics/angular": "^14.2.8",
"typescript": "~4.7.2"
},
"devDependencies": {
"@types/node": "^14.15.0"
},
"engines": {
"node": ">=14.1.0"
}
},
"packages/testserver": {
"name": "@pptr/testserver",
"version": "0.6.0",
@ -8524,6 +8799,74 @@
}
},
"dependencies": {
"@angular-devkit/core": {
"version": "14.2.7",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.7.tgz",
"integrity": "sha512-83SCYP3h6fglWMgAXFDc8HfOxk9t3ugK0onATXchctvA7blW4Vx8BSg3/DgbqCv+fF380SN8bYqqLJl8fQFdzg==",
"requires": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
},
"dependencies": {
"jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg=="
},
"source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
}
}
},
"@angular-devkit/schematics": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.2.8.tgz",
"integrity": "sha512-L5GEgueZV4vqZy9Ar0zxVJOHK/4ttF1nPjW4Ut1vRFJGxsHFVEpxq5eGBf2JYSiOhqmFYc6GnJOxA6C4xAIHjA==",
"requires": {
"@angular-devkit/core": "14.2.8",
"jsonc-parser": "3.1.0",
"magic-string": "0.26.2",
"ora": "5.4.1",
"rxjs": "6.6.7"
},
"dependencies": {
"@angular-devkit/core": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.8.tgz",
"integrity": "sha512-30nDq2PH91X7T42xXFBlTiXTBG143z0BL8IUgpVCxTFYwxgPbtV4bcXTkiBgh1FL/usZcHa0Bd/64wxmFOpYwA==",
"requires": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
}
},
"jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg=="
},
"magic-string": {
"version": "0.26.2",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.2.tgz",
"integrity": "sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==",
"requires": {
"sourcemap-codec": "^1.4.8"
}
},
"source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
}
}
},
"@babel/code-frame": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
@ -9530,6 +9873,23 @@
"puppeteer": "file:../packages/puppeteer"
}
},
"@puppeteer/ng-schematics": {
"version": "file:packages/ng-schematics",
"requires": {
"@angular-devkit/core": "^14.2.6",
"@angular-devkit/schematics": "^14.2.6",
"@schematics/angular": "^14.2.8",
"@types/node": "^14.15.0"
},
"dependencies": {
"@types/node": {
"version": "14.18.33",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.33.tgz",
"integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==",
"dev": true
}
}
},
"@rushstack/node-core-library": {
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.52.0.tgz",
@ -9602,6 +9962,44 @@
"string-argv": "~0.3.1"
}
},
"@schematics/angular": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.2.8.tgz",
"integrity": "sha512-SuzeCpWHF9+8jey7WheM1Va0iyJrYAD88O2VT2x0NEF2PXEH63lV7BCBtE7kKurIAmXBbvTCsPyZuFKYJGDHFA==",
"dev": true,
"requires": {
"@angular-devkit/core": "14.2.8",
"@angular-devkit/schematics": "14.2.8",
"jsonc-parser": "3.1.0"
},
"dependencies": {
"@angular-devkit/core": {
"version": "14.2.8",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.8.tgz",
"integrity": "sha512-30nDq2PH91X7T42xXFBlTiXTBG143z0BL8IUgpVCxTFYwxgPbtV4bcXTkiBgh1FL/usZcHa0Bd/64wxmFOpYwA==",
"dev": true,
"requires": {
"ajv": "8.11.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.1.0",
"rxjs": "6.6.7",
"source-map": "0.7.4"
}
},
"jsonc-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz",
"integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==",
"dev": true
},
"source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
"dev": true
}
}
},
"@sinonjs/commons": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
@ -10081,7 +10479,6 @@
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz",
"integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
@ -10089,6 +10486,14 @@
"uri-js": "^4.2.2"
}
},
"ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"requires": {
"ajv": "^8.0.0"
}
},
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@ -10393,11 +10798,15 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
"dev": true,
"requires": {
"restore-cursor": "^3.1.0"
}
},
"cli-spinners": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz",
"integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw=="
},
"cli-width": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
@ -10415,6 +10824,11 @@
"wrap-ansi": "^7.0.0"
}
},
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -10606,6 +11020,14 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
"integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
"requires": {
"clone": "^1.0.2"
}
},
"define-properties": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
@ -11467,8 +11889,7 @@
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-diff": {
"version": "1.2.0",
@ -12116,6 +12537,11 @@
"is-extglob": "^2.1.1"
}
},
"is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="
},
"is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@ -12394,8 +12820,7 @@
"json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@ -12649,8 +13074,7 @@
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"min-indent": {
"version": "1.0.1",
@ -13078,7 +13502,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"requires": {
"mimic-fn": "^2.1.0"
}
@ -13097,6 +13520,22 @@
"word-wrap": "^1.2.3"
}
},
"ora": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
"integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
"requires": {
"bl": "^4.1.0",
"chalk": "^4.1.0",
"cli-cursor": "^3.1.0",
"cli-spinners": "^2.5.0",
"is-interactive": "^1.0.0",
"is-unicode-supported": "^0.1.0",
"log-symbols": "^4.1.0",
"strip-ansi": "^6.0.0",
"wcwidth": "^1.0.1"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@ -13292,8 +13731,7 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"puppeteer": {
"version": "file:packages/puppeteer",
@ -13558,8 +13996,7 @@
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"resolve": {
"version": "1.17.0",
@ -13589,7 +14026,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
"dev": true,
"requires": {
"onetime": "^5.1.0",
"signal-exit": "^3.0.2"
@ -13702,7 +14138,6 @@
"version": "6.6.7",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
}
@ -13781,8 +14216,7 @@
"signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"sinon": {
"version": "14.0.0",
@ -13823,8 +14257,7 @@
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
},
"spdx-correct": {
"version": "3.1.1",
@ -14209,8 +14642,7 @@
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"tsutils": {
"version": "3.21.0",
@ -14291,7 +14723,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
"requires": {
"punycode": "^2.1.0"
}
@ -14346,6 +14777,14 @@
"integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==",
"dev": true
},
"wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
"integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
"requires": {
"defaults": "^1.0.3"
}
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",

22
packages/ng-schematics/.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# Outputs
src/**/*.js
src/**/*.js.map
src/**/*.d.ts
# Keep files that serve as template
!src/**/files/**/*
# IDEs
.idea/
jsconfig.json
.vscode/
# Misc
node_modules/
npm-debug.log*
yarn-error.log*
# Mac OSX Finder files.
**/.DS_Store
.DS_Store

View File

@ -0,0 +1,6 @@
module.exports = {
logLevel: 'debug',
spec: 'test/build/**/*.spec.js',
exit: !!process.env.CI,
reporter: process.env.CI ? 'spec' : 'dot',
};

View File

@ -0,0 +1,27 @@
# Puppeteer Schematics Angular
This schematics provide a simple set up of Puppeteer for an Angular project.
## Usage
Run the command in an Angular CLI app directory.
_Note this will add the schematic as a dependency to your project._
```bash
ng add puppetter-schematics
```
With the schematics installed, you can run E2E tests with your chose:
```bash
npm run e2e
# or yarn e2e
```
### Unit Testing
The schematics utilize `@angular-devkit/schematics/testing` for verifying correct file creation and `package.json` updates. To execute the test suit:
```bash
npm run test
```

View File

@ -0,0 +1,70 @@
/**
* Copyright 2022 Google Inc. 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.
*/
const fs = require('fs/promises');
const path = require('path');
/**
*
* @param {String} directory
* @param {String[]} files
*/
async function findSchemaFiles(directory, files = []) {
const items = await fs.readdir(directory);
const promises = [];
// Match any listing that has no *.* format
// Ignore files folder
const regEx = /^.*\.[^\s]*$/;
items.forEach(item => {
if (!item.match(regEx)) {
promises.push(findSchemaFiles(`${directory}/${item}`, files));
} else if (item.endsWith('.json') || directory.includes('files')) {
files.push(`${directory}/${item}`);
}
});
await Promise.all(promises);
return files;
}
async function copySchemaFiles() {
const srcDir = './src';
const outputDir = './lib';
const files = await findSchemaFiles(srcDir);
const moves = files.map(file => {
const to = file.replace(srcDir, outputDir);
return {from: file, to};
});
// Because fs.cp is Experimental (recursive support)
// We need to create directories first and copy the files
await Promise.all(
moves.map(({to}) => {
const dir = path.dirname(to);
return fs.mkdir(dir, {recursive: true});
})
);
await Promise.all(
moves.map(({from, to}) => {
return fs.copyFile(from, to);
})
);
}
copySchemaFiles();

1098
packages/ng-schematics/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
{
"name": "@puppeteer/ng-schematics",
"version": "0.0.0",
"description": "Puppeteer Angular schematics",
"scripts": {
"copy": "node copySchemaFiles.js",
"clean": "tsc -b --clean && rimraf lib",
"dev": "npm run copy && tsc -p tsconfig.json --watch",
"build": "run-s build:*",
"build:schematics": "npm run copy && tsc -p tsconfig.json",
"build:test": "tsc -p tsconfig.spec.json",
"test": "run-s build && mocha"
},
"keywords": [
"angular",
"puppeteer",
"schematics"
],
"author": "The Chromium Authors",
"license": "Apache-2.0",
"engines": {
"node": ">=14.1.0"
},
"dependencies": {
"@angular-devkit/core": "^14.2.6",
"@angular-devkit/schematics": "^14.2.6"
},
"devDependencies": {
"@types/node": "^14.15.0",
"@schematics/angular": "^14.2.8"
},
"ng-add": {
"save": "devDependencies"
},
"schematics": "./lib/schematics/collection.json"
}

View File

@ -0,0 +1,10 @@
{
"$schema": "../../../../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"ng-add": {
"description": "Add Puppeteer to an Angular project",
"factory": "./ng-add/index#ngAdd",
"schema": "./ng-add/schema.json"
}
}
}

View File

@ -0,0 +1,4 @@
/**
* @type {import("puppeteer").Configuration}
*/
module.exports = {};

View File

@ -0,0 +1,29 @@
import * as puppeteer from 'puppeteer';
describe('App test', function () {
let browser: puppeteer.Browser;
let page: puppeteer.Page;
beforeAll(async () => {
browser = await puppeteer.launch();
});
beforeEach(async () => {
page = await browser.newPage();
await page.goto('<%= baseUrl %>');
});
afterEach(async () => {
await page.close();
});
it('is running', async function () {
const element = await page.waitForSelector(
'text/<%= project %> app is running!'
);
<% if(testingFramework == 'jasmine') { %>
expect(element).not.toBeNull();
<% } %>
});
});

View File

@ -0,0 +1,8 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["<%= testingFramework %>"]
},
"include": ["tests/**/*.e2e.ts"]
}

View File

@ -0,0 +1,4 @@
require('@babel/register')({
extensions: ['.js', '.ts'],
presets: ['@babel/preset-env', '@babel/preset-typescript'],
});

View File

@ -0,0 +1,9 @@
{
"spec_dir": "e2e",
"spec_files": ["**/*[eE]2[eE].ts"],
"helpers": ["helpers/babel.js", "helpers/**/*.{js|ts}"],
"env": {
"stopSpecOnExpectationFailure": false,
"random": true
}
}

View File

@ -0,0 +1,112 @@
/**
* Copyright 2022 Google Inc. 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
*
* https://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.
*/
import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks';
import {concatMap, map, scan} from 'rxjs/operators';
import {of} from 'rxjs';
import {
addBaseFiles,
addFrameworkFiles,
getScriptFromOptions,
} from '../utils/files.js';
import {
addPackageJsonDependencies,
addPackageJsonScripts,
getDependenciesFromOptions,
getPackageLatestNpmVersion,
DependencyType,
type NodePackage,
} from '../utils/packages.js';
import {type SchematicsOptions} from '../utils/types.js';
import {getAngularConfig} from '../utils/json.js';
// You don't have to export the function as default. You can also have more than one rule
// factory per file.
export function ngAdd(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
return chain([
addDependencies(options),
addPuppeteerFiles(options),
addOtherFiles(options),
updateScripts(options),
])(tree, context);
};
}
function addDependencies(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding dependencies to "package.json"');
const dependencies = getDependenciesFromOptions(options);
return of(...dependencies).pipe(
concatMap((packageName: string) => {
return getPackageLatestNpmVersion(packageName);
}),
scan((array, nodePackage) => {
array.push(nodePackage);
return array;
}, [] as NodePackage[]),
map(packages => {
context.logger.debug('Updating dependencies...');
addPackageJsonDependencies(tree, packages, DependencyType.Dev);
context.addTask(new NodePackageInstallTask());
return tree;
})
);
};
}
function updateScripts(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext): Tree => {
context.logger.debug('Updating "package.json" scripts');
const script = getScriptFromOptions(options);
return addPackageJsonScripts(tree, [
{
name: 'e2e',
script,
},
]);
};
}
function addPuppeteerFiles(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding Puppeteer base files');
const {projects} = getAngularConfig(tree);
return addBaseFiles(tree, context, {
projects,
options,
});
};
}
function addOtherFiles(options: SchematicsOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
context.logger.debug('Adding Puppeteer additional files');
const {projects} = getAngularConfig(tree);
return addFrameworkFiles(tree, context, {
projects,
options,
});
};
}

View File

@ -0,0 +1,31 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "Puppeteer",
"title": "Puppeteer Install Schema",
"type": "object",
"properties": {
"exportConfig": {
"description": "",
"type": "boolean",
"default": false,
"x-prompt": "Do you wish to export default Puppeteer config file?"
},
"testingFramework": {
"description": "",
"type": "string",
"enum": ["jasmine"],
"default": "jasmine",
"x-prompt": {
"message": "With what Testing Library do you wish to integrate?",
"type": "list",
"items": [
{
"value": "jasmine",
"label": "Use Jasmine [https://jasmine.github.io/]"
}
]
}
}
},
"required": []
}

View File

@ -0,0 +1,131 @@
import {getSystemPath, normalize, strings} from '@angular-devkit/core';
import {
SchematicContext,
SchematicsException,
Tree,
apply,
applyTemplates,
chain,
filter,
mergeWith,
move,
url,
} from '@angular-devkit/schematics';
import {relative, resolve} from 'path';
import {SchematicsOptions, TestingFramework} from './types.js';
export interface FilesOptions {
projects: any;
options: SchematicsOptions;
applyPath: string;
relativeToWorkspacePath: string;
movePath?: string;
filterPredicate?: (path: string) => boolean;
}
const PUPPETEER_CONFIG_TEMPLATE = '.puppeteerrc.cjs.template';
export function addFiles(
tree: Tree,
context: SchematicContext,
{
projects,
options,
applyPath,
movePath,
relativeToWorkspacePath,
filterPredicate,
}: FilesOptions
): any {
return chain(
Object.keys(projects).map(name => {
const project = projects[name];
const projectPath = resolve(getSystemPath(normalize(project.root)));
const workspacePath = resolve(getSystemPath(normalize('')));
const relativeToWorkspace = relative(
`${projectPath}${relativeToWorkspacePath}`,
workspacePath
);
const baseUrl = getProjectBaseUrl(project);
return mergeWith(
apply(url(applyPath), [
filter(
filterPredicate ??
(() => {
return true;
})
),
move(movePath ? `${project.root}${movePath}` : project.root),
applyTemplates({
...options,
...strings,
root: project.root ? `${project.root}/` : project.root,
baseUrl,
project: name,
relativeToWorkspace,
}),
])
);
})
)(tree, context);
}
function getProjectBaseUrl(project: any): string {
let options = {protocol: 'http', port: 4200, host: 'localhost'};
if (project.architect?.serve?.options) {
const projectOptions = project.architect?.serve?.options;
options = {...options, ...projectOptions};
options.protocol = projectOptions.ssl ? 'https' : 'http';
}
return `${options.protocol}://${options.host}:${options.port}`;
}
export function addBaseFiles(
tree: Tree,
context: SchematicContext,
filesOptions: Omit<FilesOptions, 'applyPath' | 'relativeToWorkspacePath'>
): any {
const options: FilesOptions = {
...filesOptions,
applyPath: './files/base',
relativeToWorkspacePath: `/`,
filterPredicate: path => {
return path.includes(PUPPETEER_CONFIG_TEMPLATE) &&
!filesOptions.options.exportConfig
? false
: true;
},
};
return addFiles(tree, context, options);
}
export function addFrameworkFiles(
tree: Tree,
context: SchematicContext,
filesOptions: Omit<FilesOptions, 'applyPath' | 'relativeToWorkspacePath'>
): any {
const testingFramework = filesOptions.options.testingFramework;
const options: FilesOptions = {
...filesOptions,
applyPath: `./files/${testingFramework}`,
relativeToWorkspacePath: `/`,
};
return addFiles(tree, context, options);
}
export function getScriptFromOptions(options: SchematicsOptions): string {
switch (options.testingFramework) {
case TestingFramework.Jasmine:
return 'jasmine --config=./e2e/support/jasmine.json';
default:
throw new SchematicsException('Testing framework not supported.');
}
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2022 Google Inc. 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
*
* https://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.
*/
import {SchematicsException, Tree} from '@angular-devkit/schematics';
export function getJsonFileAsObject(
tree: Tree,
path: string
): Record<string, any> {
try {
const buffer = tree.read(path) as Buffer;
const content = buffer.toString();
return JSON.parse(content);
} catch {
throw new SchematicsException(`Unable to retrieve file at ${path}.`);
}
}
export function getObjectAsJson(object: Record<string, any>): string {
return JSON.stringify(object, null, 2);
}
export function getAngularConfig(tree: Tree): Record<string, any> {
return getJsonFileAsObject(tree, './angular.json');
}

View File

@ -0,0 +1,148 @@
/**
* Copyright 2022 Google Inc. 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
*
* https://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.
*/
import {SchematicsException, Tree} from '@angular-devkit/schematics';
import {get} from 'https';
import {SchematicsOptions, TestingFramework} from './types.js';
import {getJsonFileAsObject, getObjectAsJson} from './json.js';
export interface NodePackage {
name: string;
version: string;
}
export interface NodeScripts {
name: string;
script: string;
}
export enum DependencyType {
Default = 'dependencies',
Dev = 'devDependencies',
Peer = 'peerDependencies',
Optional = 'optionalDependencies',
}
export function getPackageLatestNpmVersion(name: string): Promise<NodePackage> {
return new Promise(resolve => {
let version = 'latest';
return get(`https://registry.npmjs.org/${name}`, res => {
let data = '';
res.on('data', (chunk: any) => {
data += chunk;
});
res.on('end', () => {
try {
const response = JSON.parse(data);
version = response?.['dist-tags']?.latest ?? version;
} catch {
} finally {
resolve({
name,
version,
});
}
});
}).on('error', () => {
resolve({
name,
version,
});
});
});
}
function updateJsonValues(
json: Record<string, any>,
target: string,
updates: Array<{name: string; value: string}>,
overwrite = false
) {
updates.forEach(({name, value}) => {
if (!json[target][name] || overwrite) {
json[target] = {
...json[target],
[name]: value,
};
}
});
}
export function addPackageJsonDependencies(
tree: Tree,
packages: NodePackage[],
type: DependencyType,
overwrite?: boolean,
fileLocation = './package.json'
): Tree {
const packageJson = getJsonFileAsObject(tree, fileLocation);
updateJsonValues(
packageJson,
type,
packages.map(({name, version}) => {
return {name, value: version};
}),
overwrite
);
tree.overwrite(fileLocation, getObjectAsJson(packageJson));
return tree;
}
export function getDependenciesFromOptions(
options: SchematicsOptions
): string[] {
const dependencies = ['puppeteer'];
switch (options.testingFramework) {
case TestingFramework.Jasmine:
dependencies.push(
'jasmine',
'@babel/core',
'@babel/register',
'@babel/preset-env',
'@babel/preset-typescript'
);
break;
default:
throw new SchematicsException(`Testing framework not supported.`);
}
return dependencies;
}
export function addPackageJsonScripts(
tree: Tree,
scripts: NodeScripts[],
overwrite?: boolean,
fileLocation = './package.json'
): Tree {
const packageJson = getJsonFileAsObject(tree, fileLocation);
updateJsonValues(
packageJson,
'scripts',
scripts.map(({name, script}) => {
return {name, value: script};
}),
overwrite
);
tree.overwrite(fileLocation, getObjectAsJson(packageJson));
return tree;
}

View File

@ -0,0 +1,27 @@
/**
* Copyright 2022 Google Inc. 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
*
* https://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.
*/
export enum TestingFramework {
Jasmine = 'jasmine',
Jest = 'jest',
Mocha = 'mocha',
Node = 'node',
}
export interface SchematicsOptions {
testingFramework: TestingFramework;
exportConfig?: boolean;
}

View File

@ -0,0 +1,127 @@
import expect from 'expect';
import sinon from 'sinon';
import https from 'https';
import {join} from 'path';
import {
SchematicTestRunner,
UnitTestTree,
} from '@angular-devkit/schematics/testing/schematic-test-runner';
import {JsonObject} from '@angular-devkit/core';
const WORKSPACE_OPTIONS = {
name: 'workspace',
newProjectRoot: 'projects',
version: '14.0.0',
};
const APPLICATION_OPTIONS = {
name: 'sandbox',
};
function getProjectFile(file: string): string {
return `/${WORKSPACE_OPTIONS.newProjectRoot}/${APPLICATION_OPTIONS.name}/${file}`;
}
function getPackageJson(tree: UnitTestTree): {
scripts: Record<string, string>;
devDependencies: string[];
} {
const packageJson = tree.readJson('package.json') as JsonObject;
return {
scripts: packageJson['scripts'] as any,
devDependencies: Object.keys(
packageJson['devDependencies'] as Record<string, string>
),
};
}
async function buildTestingTree(userOptions?: Record<string, any>) {
const runner = new SchematicTestRunner(
'schematics',
join(__dirname, '../../lib/schematics/collection.json')
);
const options = {
exportConfig: false,
testingFramework: 'jasmine',
...userOptions,
};
let workingTree: UnitTestTree;
// Build workspace
workingTree = await runner
.runExternalSchematicAsync(
'@schematics/angular',
'workspace',
WORKSPACE_OPTIONS
)
.toPromise();
// Build dummy application
workingTree = await runner
.runExternalSchematicAsync(
'@schematics/angular',
'application',
APPLICATION_OPTIONS,
workingTree
)
.toPromise();
return await runner
.runSchematicAsync('ng-add', options, workingTree)
.toPromise();
}
describe('@puppeteer/ng-schematics: ng-add', () => {
// Stop outgoing Request for version fetching
before(() => {
const httpsGetStub = sinon.stub(https, 'get');
httpsGetStub.returns({
on: (_: any, callback: () => void) => {
callback();
},
} as any);
});
after(() => {
sinon.restore();
});
it('should create base files and update to "package.json"', async () => {
const tree = await buildTestingTree();
const {devDependencies} = getPackageJson(tree);
expect(tree.files).toContain(getProjectFile('e2e/tsconfig.json'));
expect(tree.files).toContain(getProjectFile('e2e/tests/app.e2e.ts'));
expect(devDependencies).toContain('puppeteer');
});
it('should create Puppeteer config', async () => {
const {files} = await buildTestingTree({
exportConfig: true,
});
expect(files).toContain(getProjectFile('.puppeteerrc.cjs'));
});
it('should not create Puppeteer config', async () => {
const {files} = await buildTestingTree({
exportConfig: false,
});
expect(files).not.toContain(getProjectFile('.puppeteerrc.cjs'));
});
it('should create Jasmine files and update "package.json"', async () => {
const tree = await buildTestingTree({
testingFramework: 'jasmine',
});
const {scripts, devDependencies} = getPackageJson(tree);
expect(tree.files).toContain(getProjectFile('e2e/support/jasmine.json'));
expect(tree.files).toContain(getProjectFile('e2e/helpers/babel.js'));
expect(scripts['e2e']).toBe('jasmine --config=./e2e/support/jasmine.json');
expect(devDependencies).toContain('jasmine');
expect(devDependencies).toContain('@babel/core');
expect(devDependencies).toContain('@babel/register');
expect(devDependencies).toContain('@babel/register');
});
});

View File

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"baseUrl": "tsconfig",
"lib": ["es2018", "dom"],
"module": "CommonJS",
"noEmitOnError": true,
"rootDir": "src/",
"outDir": "lib/",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"types": ["node"],
"target": "ES6"
},
"include": ["src/**/*"],
"exclude": ["src/**/files/**/*"]
}

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"rootDir": "test/src/",
"outDir": "test/build/",
"types": ["node", "mocha"]
},
"include": ["test/**/*"],
"exclude": ["test/build/**/*"]
}

View File

@ -22,7 +22,7 @@ from tempfile import mktemp
def main():
for package_json_path in glob("packages/*/package.json") + ["website/package.json"]:
for package_json_path in ["packages/puppeteer-core/package.json","packages/puppeteer/package.json","website/package.json"]:
print(package_json_path)
tmp_file_path = mktemp()
with open(tmp_file_path, 'w') as tmp_file: