generator-nitro 7.3.0 → 7.5.0
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/generators/app/templates/.node-version +1 -1
- package/generators/app/templates/.prettierignore +1 -0
- package/generators/app/templates/CUTAWAY.gitignore +3 -1
- package/generators/app/templates/CUTAWAYpackage.json +34 -29
- package/generators/app/templates/config/default.js +0 -6
- package/generators/app/templates/config/webpack/options.js +2 -5
- package/generators/app/templates/project/docs/nitro-config.md +0 -16
- package/generators/app/templates/project/docs/nitro.md +1 -1
- package/generators/app/templates/src/patterns/atoms/box/css/modifier/box-dark.scss +0 -1
- package/generators/app/templates/src/patterns/atoms/stage/css/stage.scss +7 -6
- package/generators/app/templates/src/patterns/molecules/example/css/modifier/example-blue.scss +10 -3
- package/generators/app/templates/src/shared/base/grid/css/variables/grid.scss +2 -2
- package/generators/app/templates/src/shared/base/webfonts/css/webfont-gaegu.scss +6 -15
- package/generators/app/templates/src/shared/base/webfonts/css/webfont-playfair-display.scss +12 -20
- package/generators/app/templates/src/shared/utils/fixed-aspect-ratio/css/fixed-aspect-ratio.scss +4 -6
- package/generators/app/templates/src/shared/utils/typo/css/typo.scss +19 -16
- package/generators/app/templates/src/shared/utils/z-index/css/z-index.scss +1 -0
- package/generators/app/templates/stylelint.config.js +18 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/clickAndHoverHelper.js +43 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/interceptImages.js +31 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/loadCookies.js +16 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/onBefore.js +3 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/onReady.js +6 -0
- package/generators/app/templates/tests/backstop/engine_scripts/playwright/overrideCSS.js +27 -0
- package/generators/app/templates/tests/backstop/engine_scripts/puppet/clickAndHoverHelper.js +39 -39
- package/generators/app/templates/tests/backstop/engine_scripts/puppet/ignoreCSP.js +1 -1
- package/generators/app/templates/tests/backstop/readme.md +1 -1
- package/generators/app/templates/tests/cypress/cypress/e2e/pages/404.cy.js +9 -6
- package/generators/app/templates/tests/cypress/cypress/e2e/pages/index.cy.js +5 -5
- package/generators/app/templates/tests/cypress/readme.md +2 -2
- package/generators/app/templates/tests/playwright/e2e/pages/404.spec.ts +41 -0
- package/generators/app/templates/tests/playwright/e2e/pages/index.spec.ts +42 -0
- package/generators/app/templates/tests/playwright/playwright.config.ts +108 -0
- package/generators/app/templates/tests/playwright/readme.md +24 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
18.
|
|
1
|
+
18.16.0
|
|
@@ -40,11 +40,13 @@ debug.log
|
|
|
40
40
|
/project/tmp
|
|
41
41
|
/public/assets
|
|
42
42
|
/public/proto
|
|
43
|
-
/public/reports
|
|
43
|
+
/public/reports/**/*
|
|
44
|
+
!/public/reports/lighthouse/
|
|
44
45
|
/src/patterns/**/template/*.js
|
|
45
46
|
/src/patterns/**/template/partial/*.js
|
|
46
47
|
/tests/cypress/cypress/screenshots
|
|
47
48
|
/tests/cypress/cypress/videos
|
|
49
|
+
/tests/playwright/test-results/
|
|
48
50
|
|
|
49
51
|
# allow
|
|
50
52
|
!.gitkeep
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"private": true,
|
|
7
7
|
"author": "The Nitro Team",
|
|
8
8
|
"engines": {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
"node": ">=14.15.0 <19",
|
|
10
|
+
"npm": ">=6.14.8 <10"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"\n# PROJECT ------- ": "",
|
|
@@ -23,25 +23,28 @@
|
|
|
23
23
|
"postinstall": "<% if (git.root) { %>cd <%= git.root %> && husky install <% if (git.project) { %><%= git.project %>/.husky && cd <%= git.project %> <% } %>&& <% } %><% if (options.themes) { %>npm rebuild node-sass && <% } %>env-linter<% if (git.root) { %> --hooksInstalled<% } %> --saveExact --dependenciesExactVersion --lts",
|
|
24
24
|
"\n# LINT/TEST ------- ": "",
|
|
25
25
|
"check-node-version": "check-node-version --print --package",
|
|
26
|
-
"cypress-test": "npm run build && cross-env PORT=8888 NITRO_MODE=test npm-run-all --parallel --race
|
|
26
|
+
"cypress-test": "npm run build && cross-env PORT=8888 NITRO_MODE=test npm-run-all --parallel --race prod:serve cypress-test:open",
|
|
27
27
|
"cypress-test:open": "cypress open --project ./tests/cypress/ --e2e --browser chrome",
|
|
28
|
-
"lighthouse-test": "npm run build && cross-env PORT=
|
|
29
|
-
"lighthouse-test:
|
|
30
|
-
"lighthouse-test:run": "lighthouse http://localhost:8890/<% if (options.exampleCode) { %>example-patterns<% } else { %>index<% } %> --quiet --configPath=./tests/lighthouse/lighthouse.config.js --output-path=./public/reports/lighthouse/report.html --view",
|
|
28
|
+
"lighthouse-test": "npm run build && cross-env PORT=8889 NITRO_MODE=test npm-run-all --parallel --race prod:serve lighthouse-test:run",
|
|
29
|
+
"lighthouse-test:run": "lighthouse http://localhost:8889/<% if (options.exampleCode) { %>example-patterns<% } else { %>index<% } %> --quiet --configPath=./tests/lighthouse/lighthouse.config.js --output-path=./public/reports/lighthouse/report.html --view",
|
|
31
30
|
"lint": "npm-run-all lint:*",
|
|
32
31
|
"lint:css": "stylelint src/**/*.*ss --allow-empty-input",
|
|
33
32
|
"lint:data": "nitro-app-validate-pattern-data",
|
|
34
33
|
"lint:html": "gulp lint-html",
|
|
35
34
|
"lint:js": "eslint ./src --ext <% if (options.jsCompiler === 'js') { %>.js,.jsx<% } else { %>.ts,.tsx<% } %>",
|
|
36
35
|
"lint:license": "license-checker --production --summary --exclude \"Apache-2.0, BSD, ISC, LGPL, MIT, MPL\" --failOn \"AGPL; EPL; GPL\"",
|
|
37
|
-
"
|
|
36
|
+
"playwright-test": "cross-env PORT=8890 NITRO_MODE=test playwright test --config=tests/playwright/playwright.config.ts --ui",
|
|
37
|
+
"prettier": "prettier --write \"**/*.*(js|jsx|ts|tsx|json|css|scss|md|mdx|graphql|gql|yml|yaml)\"",
|
|
38
38
|
"test": "npm-run-all test:*",
|
|
39
39
|
"test:lint": "npm run lint",
|
|
40
|
-
"test:
|
|
41
|
-
"test:
|
|
42
|
-
"test:
|
|
40
|
+
"test:build": "npm run build",
|
|
41
|
+
"test:e2e": "cross-env PORT=8899 NITRO_MODE=test npm-run-all --parallel --race test:e2e:*",
|
|
42
|
+
"test:e2e:serve": "npm run prod:serve",
|
|
43
|
+
"test:e2e:run": "npm-run-all --serial test:e2e:run:*",
|
|
44
|
+
"test:e2e:run:cypress": "cypress run --project ./tests/cypress/",
|
|
45
|
+
"test:e2e:run:playwright": "playwright test --config=tests/playwright/playwright.config.ts",
|
|
43
46
|
"visual-approve": "backstop approve --config=tests/backstop/backstop.config.js --docker",
|
|
44
|
-
"visual-test": "npm run build && cross-env PORT=
|
|
47
|
+
"visual-test": "npm run build && cross-env PORT=8892 npm-run-all --parallel --race visual-test:*",
|
|
45
48
|
"visual-test:serve": "npm run prod:serve",
|
|
46
49
|
"visual-test:test": "backstop test --config=tests/backstop/backstop.config.js --docker",
|
|
47
50
|
"\n# BUILD/RELEASE ------- ": "",
|
|
@@ -84,38 +87,39 @@
|
|
|
84
87
|
"@gondel/core": "1.2.7",
|
|
85
88
|
"@gondel/plugin-hot": "1.2.7",
|
|
86
89
|
"bootstrap": "5.2.3",<% } %>
|
|
87
|
-
"core-js": "3.
|
|
90
|
+
"core-js": "3.30.1"<% if (options.exampleCode) { %>,
|
|
88
91
|
"flatpickr": "4.6.13",
|
|
89
92
|
"handlebars": "4.7.7",
|
|
90
93
|
"jquery": "3.6.4",
|
|
91
94
|
"lazysizes": "5.3.2",
|
|
92
|
-
"lottie-web": "5.
|
|
93
|
-
"prevent-window-opener-attacks": "0.3.
|
|
95
|
+
"lottie-web": "5.11.0",
|
|
96
|
+
"prevent-window-opener-attacks": "0.3.1"<% } %><% if (options.jsCompiler === 'js') { %>,
|
|
94
97
|
"regenerator-runtime": "0.13.11"<% } %><% if (options.exampleCode) { %>,
|
|
95
98
|
"svg4everybody": "2.1.9"<% } %>
|
|
96
99
|
},
|
|
97
100
|
"devDependencies": {<% if (options.jsCompiler === 'js') { %>
|
|
98
|
-
"@babel/eslint-parser": "7.
|
|
101
|
+
"@babel/eslint-parser": "7.21.3",<% } %>
|
|
99
102
|
"@khanacademy/tota11y": "0.2.0",
|
|
100
103
|
"@merkle-open/eslint-config": "1.0.0",
|
|
101
104
|
"@merkle-open/html-validate-config": "1.0.1",
|
|
102
|
-
"@merkle-open/prettier-config": "1.0
|
|
103
|
-
"@merkle-open/stylelint-config": "1.0
|
|
104
|
-
"@merkle-open/ts-config": "1.0
|
|
105
|
+
"@merkle-open/prettier-config": "1.1.0",
|
|
106
|
+
"@merkle-open/stylelint-config": "2.1.0",
|
|
107
|
+
"@merkle-open/ts-config": "1.1.0",
|
|
105
108
|
"@nitro/app": "<%= version %>",
|
|
106
109
|
"@nitro/exporter": "<%= version %>",
|
|
107
110
|
"@nitro/gulp": "<%= version %>",
|
|
108
|
-
"@nitro/webpack": "<%= version %>"
|
|
111
|
+
"@nitro/webpack": "<%= version %>",
|
|
112
|
+
"@playwright/test": "1.33.0",<% if (options.jsCompiler === 'ts') { %>
|
|
109
113
|
"@types/bootstrap": "5.2.6",<% if (options.exampleCode ) { %>
|
|
110
114
|
"@types/jquery": "3.5.16",<% } %>
|
|
111
115
|
"@types/svg4everybody": "2.1.2",
|
|
112
116
|
"@types/webpack-env": "1.18.0",<% } %>
|
|
113
|
-
"backstopjs": "6.1
|
|
117
|
+
"backstopjs": "6.2.1",
|
|
114
118
|
"check-node-version": "4.2.1",
|
|
115
119
|
"commitizen": "4.3.0",
|
|
116
120
|
"config": "3.3.9",
|
|
117
121
|
"cross-env": "7.0.3",
|
|
118
|
-
"cypress": "12.
|
|
122
|
+
"cypress": "12.11.0",
|
|
119
123
|
"cz-conventional-changelog": "3.3.0",
|
|
120
124
|
"env-linter": "1.0.0",
|
|
121
125
|
"eslint": "7.32.0",
|
|
@@ -123,18 +127,18 @@
|
|
|
123
127
|
"extend": "3.0.2",
|
|
124
128
|
"generator-nitro": "<%= version %>",
|
|
125
129
|
"gulp": "4.0.2",
|
|
130
|
+
"html-validate": "7.15.1",
|
|
126
131
|
"husky": "8.0.3",
|
|
127
|
-
"html-validate": "7.13.3",
|
|
128
132
|
"license-checker": "25.0.1",
|
|
129
|
-
"lighthouse": "10.
|
|
130
|
-
"lint-staged": "13.2.
|
|
133
|
+
"lighthouse": "10.1.1",
|
|
134
|
+
"lint-staged": "13.2.2",<% if (options.themes) { %>
|
|
131
135
|
"node-sass": "8.0.0",<% } %>
|
|
132
|
-
"npm-check-updates": "16.
|
|
136
|
+
"npm-check-updates": "16.10.9",
|
|
133
137
|
"npm-run-all": "4.1.5",
|
|
134
|
-
"prettier": "2.8.
|
|
135
|
-
"rimraf": "
|
|
136
|
-
"stylelint": "
|
|
137
|
-
"typescript": "
|
|
138
|
+
"prettier": "2.8.8",
|
|
139
|
+
"rimraf": "5.0.0",
|
|
140
|
+
"stylelint": "15.6.0",<% if (options.jsCompiler === 'ts') { %>
|
|
141
|
+
"typescript": "5.0.4",<% } %>
|
|
138
142
|
"webpack-cli": "4.10.0",
|
|
139
143
|
"yo": "4.3.1"
|
|
140
144
|
},
|
|
@@ -151,6 +155,7 @@
|
|
|
151
155
|
},
|
|
152
156
|
"lint-staged": {
|
|
153
157
|
"src/**/*.{css,scss}": [
|
|
158
|
+
"prettier --write",
|
|
154
159
|
"stylelint --allow-empty-input"
|
|
155
160
|
],
|
|
156
161
|
"**/*.json": [
|
|
@@ -10,9 +10,6 @@ const baseConfig = require('@nitro/app/app/core/config');
|
|
|
10
10
|
const defaultConfig = {
|
|
11
11
|
code: {
|
|
12
12
|
validation: {
|
|
13
|
-
eslint: {
|
|
14
|
-
live: false,
|
|
15
|
-
},
|
|
16
13
|
htmllint: {
|
|
17
14
|
// enabling this live validation slows down rendering
|
|
18
15
|
live: false,
|
|
@@ -22,9 +19,6 @@ const defaultConfig = {
|
|
|
22
19
|
logMissingSchemaAsError: false,
|
|
23
20
|
logMissingSchemaAsWarning: true,
|
|
24
21
|
},
|
|
25
|
-
stylelint: {
|
|
26
|
-
live: false,
|
|
27
|
-
},
|
|
28
22
|
},
|
|
29
23
|
},
|
|
30
24
|
nitro: {
|
|
@@ -4,12 +4,9 @@ const theme = process.env.THEME ? process.env.THEME : validThemes.find((theme) =
|
|
|
4
4
|
const options = {
|
|
5
5
|
rules: {
|
|
6
6
|
<% if (options.jsCompiler === 'ts') { %>js: false,
|
|
7
|
-
ts: true,<% } else { %>js:
|
|
8
|
-
eslint: config.get('code.validation.eslint.live'),
|
|
9
|
-
},
|
|
7
|
+
ts: true,<% } else { %>js: true,
|
|
10
8
|
ts: false,<% } %>
|
|
11
|
-
scss: {
|
|
12
|
-
stylelint: config.get('code.validation.stylelint.live'),<% if (options.themes) { %>
|
|
9
|
+
scss: {<% if (options.themes) { %>
|
|
13
10
|
implementation: require('node-sass'),<% } %>
|
|
14
11
|
},
|
|
15
12
|
hbs: <% if (options.clientTpl) { %>true<% } else { %>false<% } %>,
|
|
@@ -12,14 +12,6 @@ the main nodes from nitro: `code`, `nitro`,`server`, `gulp`, `feature`, `exporte
|
|
|
12
12
|
|
|
13
13
|
### Validation
|
|
14
14
|
|
|
15
|
-
#### `code.validation.eslint`
|
|
16
|
-
|
|
17
|
-
Type: Object
|
|
18
|
-
|
|
19
|
-
- `code.validation.eslint.live` - default: false
|
|
20
|
-
|
|
21
|
-
Enable/disable JavaScript linting on change.
|
|
22
|
-
|
|
23
15
|
#### `code.validation.htmllint`
|
|
24
16
|
|
|
25
17
|
Type: Object
|
|
@@ -37,14 +29,6 @@ Type: Object
|
|
|
37
29
|
- `code.validation.jsonSchema.logMissingSchemaAsError` - default: false
|
|
38
30
|
- `code.validation.jsonSchema.logMissingSchemaAsWarning` - default: true
|
|
39
31
|
|
|
40
|
-
#### `code.validation.stylelint`
|
|
41
|
-
|
|
42
|
-
Type: Object
|
|
43
|
-
|
|
44
|
-
- `code.validation.stylelint.live` - default: false
|
|
45
|
-
|
|
46
|
-
Enable/disable CSS linting on change.
|
|
47
|
-
|
|
48
32
|
## Nitro
|
|
49
33
|
|
|
50
34
|
The node `nitro` contains following properties
|
|
@@ -12,7 +12,7 @@ Nitro is simple, fast and flexible. Use this app for all your frontend work.
|
|
|
12
12
|
- Webpack Builder with HMR
|
|
13
13
|
- Gulp Tasks for additional functionality
|
|
14
14
|
- Linting, Source Maps, PostCSS & Browsersync
|
|
15
|
-
- Setup for e2e and visual regression testing (cypress, backstopjs) & lighthouse
|
|
15
|
+
- Setup for e2e and visual regression testing (playwright, cypress, backstopjs) & lighthouse
|
|
16
16
|
- Pattern generator<% if (options.clientTpl) { %>
|
|
17
17
|
- [Client side templates](./client-templates.md)<% } %><% if (options.exporter) { %>
|
|
18
18
|
- [Static Exports](./nitro-exporter.md)<% } %>
|
|
@@ -5,10 +5,7 @@
|
|
|
5
5
|
display: block;
|
|
6
6
|
width: 100%;
|
|
7
7
|
height: 190px;
|
|
8
|
-
background-image:
|
|
9
|
-
url('../img/space-ship.svg'),
|
|
10
|
-
url('../img/satellite.svg'),
|
|
11
|
-
url('../img/ufo.svg'),
|
|
8
|
+
background-image: url('../img/space-ship.svg'), url('../img/satellite.svg'), url('../img/ufo.svg'),
|
|
12
9
|
url('../img/clouds.png');
|
|
13
10
|
background-position: 10vw 200px, 50% 200px, 70% -100px, 0 0;
|
|
14
11
|
background-size: 8vw, 5vw, 7vw, auto;
|
|
@@ -18,6 +15,10 @@
|
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
@keyframes a-stage-sky {
|
|
21
|
-
from {
|
|
22
|
-
|
|
18
|
+
from {
|
|
19
|
+
background-position: 10vw 600px, 50% 200px, 70% -170px, 0 0;
|
|
20
|
+
}
|
|
21
|
+
to {
|
|
22
|
+
background-position: 20vw -200px, 120% -100px, 30% 300px, 100% 0;
|
|
23
|
+
}
|
|
23
24
|
}
|
package/generators/app/templates/src/patterns/molecules/example/css/modifier/example-blue.scss
CHANGED
|
@@ -7,7 +7,14 @@
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
@keyframes blue-background-change {
|
|
10
|
-
0%,
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
0%,
|
|
11
|
+
100% {
|
|
12
|
+
background-color: darken(desaturate($color-brand-1, 30%), 10%);
|
|
13
|
+
}
|
|
14
|
+
30% {
|
|
15
|
+
background-color: darken($color-brand-1, 20%);
|
|
16
|
+
}
|
|
17
|
+
60% {
|
|
18
|
+
background-color: darken($color-brand-1, 10%);
|
|
19
|
+
}
|
|
13
20
|
}
|
|
@@ -8,7 +8,7 @@ $grid-breakpoints: (
|
|
|
8
8
|
md: $size-md-min,
|
|
9
9
|
lg: $size-lg-min,
|
|
10
10
|
xl: $size-xl-min,
|
|
11
|
-
xxl: $size-xxl-min
|
|
11
|
+
xxl: $size-xxl-min,
|
|
12
12
|
);
|
|
13
13
|
|
|
14
14
|
$container-max-widths: (
|
|
@@ -16,5 +16,5 @@ $container-max-widths: (
|
|
|
16
16
|
md: $size-md-max,
|
|
17
17
|
lg: $size-lg-max,
|
|
18
18
|
xl: $size-xl-max,
|
|
19
|
-
xxl: $size-xl-max + 1
|
|
19
|
+
xxl: $size-xl-max + 1,
|
|
20
20
|
);
|
|
@@ -4,11 +4,8 @@
|
|
|
4
4
|
font-style: normal;
|
|
5
5
|
font-weight: 300;
|
|
6
6
|
font-display: fallback;
|
|
7
|
-
src:
|
|
8
|
-
|
|
9
|
-
local('Gaegu-Light'),
|
|
10
|
-
url('../fonts/gaegu-v2-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
11
|
-
url('../fonts/gaegu-v2-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
7
|
+
src: local('Gaegu Light'), local('Gaegu-Light'), url('../fonts/gaegu-v2-latin-300.woff2') format('woff2'),
|
|
8
|
+
url('../fonts/gaegu-v2-latin-300.woff') format('woff');
|
|
12
9
|
}
|
|
13
10
|
|
|
14
11
|
/* gaegu-regular - latin */
|
|
@@ -17,11 +14,8 @@
|
|
|
17
14
|
font-style: normal;
|
|
18
15
|
font-weight: 400;
|
|
19
16
|
font-display: fallback;
|
|
20
|
-
src:
|
|
21
|
-
|
|
22
|
-
local('Gaegu-Regular'),
|
|
23
|
-
url('../fonts/gaegu-v2-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
24
|
-
url('../fonts/gaegu-v2-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
17
|
+
src: local('Gaegu Regular'), local('Gaegu-Regular'), url('../fonts/gaegu-v2-latin-regular.woff2') format('woff2'),
|
|
18
|
+
url('../fonts/gaegu-v2-latin-regular.woff') format('woff');
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
/* gaegu-700 - latin */
|
|
@@ -30,9 +24,6 @@
|
|
|
30
24
|
font-style: normal;
|
|
31
25
|
font-weight: 700;
|
|
32
26
|
font-display: fallback;
|
|
33
|
-
src:
|
|
34
|
-
|
|
35
|
-
local('Gaegu-Bold'),
|
|
36
|
-
url('../fonts/gaegu-v2-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
37
|
-
url('../fonts/gaegu-v2-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
27
|
+
src: local('Gaegu Bold'), local('Gaegu-Bold'), url('../fonts/gaegu-v2-latin-700.woff2') format('woff2'),
|
|
28
|
+
url('../fonts/gaegu-v2-latin-700.woff') format('woff');
|
|
38
29
|
}
|
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
font-style: normal;
|
|
5
5
|
font-weight: 400;
|
|
6
6
|
font-display: fallback;
|
|
7
|
-
src:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
url('../fonts/playfair-display-v13-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
11
|
-
url('../fonts/playfair-display-v13-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
7
|
+
src: local('Playfair Display Regular'), local('PlayfairDisplay-Regular'),
|
|
8
|
+
url('../fonts/playfair-display-v13-latin-regular.woff2') format('woff2'),
|
|
9
|
+
url('../fonts/playfair-display-v13-latin-regular.woff') format('woff');
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
/* playfair-display-italic - latin */
|
|
@@ -17,11 +15,9 @@
|
|
|
17
15
|
font-style: italic;
|
|
18
16
|
font-weight: 400;
|
|
19
17
|
font-display: fallback;
|
|
20
|
-
src:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
url('../fonts/playfair-display-v13-latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
24
|
-
url('../fonts/playfair-display-v13-latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
18
|
+
src: local('Playfair Display Italic'), local('PlayfairDisplay-Italic'),
|
|
19
|
+
url('../fonts/playfair-display-v13-latin-italic.woff2') format('woff2'),
|
|
20
|
+
url('../fonts/playfair-display-v13-latin-italic.woff') format('woff');
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
/* playfair-display-700 - latin */
|
|
@@ -30,11 +26,9 @@
|
|
|
30
26
|
font-style: normal;
|
|
31
27
|
font-weight: 700;
|
|
32
28
|
font-display: fallback;
|
|
33
|
-
src:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
url('../fonts/playfair-display-v13-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
37
|
-
url('../fonts/playfair-display-v13-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
29
|
+
src: local('Playfair Display Bold'), local('PlayfairDisplay-Bold'),
|
|
30
|
+
url('../fonts/playfair-display-v13-latin-700.woff2') format('woff2'),
|
|
31
|
+
url('../fonts/playfair-display-v13-latin-700.woff') format('woff');
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
/* playfair-display-900 - latin */
|
|
@@ -43,9 +37,7 @@
|
|
|
43
37
|
font-style: normal;
|
|
44
38
|
font-weight: 900;
|
|
45
39
|
font-display: fallback;
|
|
46
|
-
src:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
url('../fonts/playfair-display-v13-latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
|
50
|
-
url('../fonts/playfair-display-v13-latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
|
40
|
+
src: local('Playfair Display Black'), local('PlayfairDisplay-Black'),
|
|
41
|
+
url('../fonts/playfair-display-v13-latin-900.woff2') format('woff2'),
|
|
42
|
+
url('../fonts/playfair-display-v13-latin-900.woff') format('woff');
|
|
51
43
|
}
|
package/generators/app/templates/src/shared/utils/fixed-aspect-ratio/css/fixed-aspect-ratio.scss
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@mixin fixed-aspect-ratio($ratio:75%, $width:100%, $display:'inline-block', $child:'>*', $elementPadding: 0) {
|
|
1
|
+
@mixin fixed-aspect-ratio($ratio: 75%, $width: 100%, $display: 'inline-block', $child: '>*', $elementPadding: 0) {
|
|
2
2
|
display: #{$display};
|
|
3
3
|
position: relative;
|
|
4
4
|
width: $width;
|
|
@@ -9,15 +9,13 @@
|
|
|
9
9
|
margin-top: $ratio;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
left: 0;
|
|
12
|
+
/* stylelint-disable-next-line */
|
|
13
|
+
#{$child} {
|
|
15
14
|
max-height: 100%;
|
|
16
15
|
padding-left: $elementPadding;
|
|
17
16
|
padding-right: $elementPadding;
|
|
18
17
|
position: absolute;
|
|
19
|
-
|
|
20
|
-
top: 0;
|
|
18
|
+
inset: 0;
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
|
|
@@ -23,13 +23,13 @@ $typography-definitions: (
|
|
|
23
23
|
mobile: (
|
|
24
24
|
'font-size': 16px,
|
|
25
25
|
'line-height': 24px,
|
|
26
|
-
'letter-spacing': 0.3px
|
|
26
|
+
'letter-spacing': 0.3px,
|
|
27
27
|
),
|
|
28
28
|
desktop: (
|
|
29
29
|
'font-size': 24px,
|
|
30
30
|
'line-height': 32px,
|
|
31
|
-
'letter-spacing': 0.75px
|
|
32
|
-
)
|
|
31
|
+
'letter-spacing': 0.75px,
|
|
32
|
+
),
|
|
33
33
|
),
|
|
34
34
|
body-small: (
|
|
35
35
|
all: (
|
|
@@ -38,13 +38,13 @@ $typography-definitions: (
|
|
|
38
38
|
mobile: (
|
|
39
39
|
'font-size': 12px,
|
|
40
40
|
'line-height': 24px,
|
|
41
|
-
'letter-spacing': 0.3px
|
|
41
|
+
'letter-spacing': 0.3px,
|
|
42
42
|
),
|
|
43
43
|
desktop: (
|
|
44
44
|
'font-size': 18px,
|
|
45
45
|
'line-height': 32px,
|
|
46
|
-
'letter-spacing': 0.75px
|
|
47
|
-
)
|
|
46
|
+
'letter-spacing': 0.75px,
|
|
47
|
+
),
|
|
48
48
|
),
|
|
49
49
|
h1: (
|
|
50
50
|
all: (
|
|
@@ -54,13 +54,13 @@ $typography-definitions: (
|
|
|
54
54
|
mobile: (
|
|
55
55
|
'font-size': 32px,
|
|
56
56
|
'line-height': 44px,
|
|
57
|
-
'letter-spacing': 0.3px
|
|
57
|
+
'letter-spacing': 0.3px,
|
|
58
58
|
),
|
|
59
59
|
desktop: (
|
|
60
60
|
'font-size': 44px,
|
|
61
61
|
'line-height': 56px,
|
|
62
|
-
'letter-spacing': 0.3px
|
|
63
|
-
)
|
|
62
|
+
'letter-spacing': 0.3px,
|
|
63
|
+
),
|
|
64
64
|
),
|
|
65
65
|
h2: (
|
|
66
66
|
all: (
|
|
@@ -70,13 +70,13 @@ $typography-definitions: (
|
|
|
70
70
|
mobile: (
|
|
71
71
|
'font-size': 24px,
|
|
72
72
|
'line-height': 32px,
|
|
73
|
-
'letter-spacing': 0.3px
|
|
73
|
+
'letter-spacing': 0.3px,
|
|
74
74
|
),
|
|
75
75
|
desktop: (
|
|
76
76
|
'font-size': 32px,
|
|
77
77
|
'line-height': 44px,
|
|
78
|
-
'letter-spacing': 0.3px
|
|
79
|
-
)
|
|
78
|
+
'letter-spacing': 0.3px,
|
|
79
|
+
),
|
|
80
80
|
),
|
|
81
81
|
button: (
|
|
82
82
|
all: (
|
|
@@ -85,13 +85,13 @@ $typography-definitions: (
|
|
|
85
85
|
mobile: (
|
|
86
86
|
'font-size': 18px,
|
|
87
87
|
'line-height': 18px,
|
|
88
|
-
'letter-spacing': 0.3px
|
|
88
|
+
'letter-spacing': 0.3px,
|
|
89
89
|
),
|
|
90
90
|
desktop: (
|
|
91
91
|
'font-size': 20px,
|
|
92
92
|
'line-height': 20px,
|
|
93
|
-
'letter-spacing': 0.3px
|
|
94
|
-
)
|
|
93
|
+
'letter-spacing': 0.3px,
|
|
94
|
+
),
|
|
95
95
|
),
|
|
96
96
|
);
|
|
97
97
|
|
|
@@ -129,7 +129,10 @@ $typography-definitions: (
|
|
|
129
129
|
@if (map-has-key(map-get($typography-definitions, $font-bundle), 'all')) {
|
|
130
130
|
$all-font-definition: map-get(map-get($typography-definitions, $font-bundle), 'all');
|
|
131
131
|
}
|
|
132
|
-
$font-definition: map-merge(
|
|
132
|
+
$font-definition: map-merge(
|
|
133
|
+
$all-font-definition,
|
|
134
|
+
map-get(map-get($typography-definitions, $font-bundle), $viewport)
|
|
135
|
+
);
|
|
133
136
|
|
|
134
137
|
@return $font-definition;
|
|
135
138
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// the first element in $layers is on the top (high z-index)
|
|
11
11
|
// The last element in $layers list is on the bottom (low z-index)
|
|
12
12
|
|
|
13
|
+
/* prettier-ignore */
|
|
13
14
|
$layers: (
|
|
14
15
|
'overlay', // overlay content incl. image overlay, ...
|
|
15
16
|
'offcanvas', // off-canvas
|
|
@@ -5,6 +5,24 @@ lintConfig.rules['plugin/stylelint-bem-namics'] = {
|
|
|
5
5
|
helperPrefixes: ['state'],
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
// remove deprecated checks - handled by prettier
|
|
9
|
+
lintConfig.rules['at-rule-name-case'] = null;
|
|
10
|
+
lintConfig.rules['color-hex-case'] = null;
|
|
11
|
+
lintConfig.rules['declaration-block-semicolon-newline-after'] = null;
|
|
12
|
+
lintConfig.rules['declaration-block-trailing-semicolon'] = null;
|
|
13
|
+
lintConfig.rules['declaration-colon-space-after'] = null;
|
|
14
|
+
lintConfig.rules['max-empty-lines'] = null;
|
|
15
|
+
lintConfig.rules['media-feature-name-case'] = null;
|
|
16
|
+
lintConfig.rules['no-missing-end-of-source-newline'] = null;
|
|
17
|
+
lintConfig.rules['number-leading-zero'] = null;
|
|
18
|
+
lintConfig.rules['property-case'] = null;
|
|
19
|
+
lintConfig.rules['selector-list-comma-newline-after'] = null;
|
|
20
|
+
lintConfig.rules['selector-pseudo-class-case'] = null;
|
|
21
|
+
lintConfig.rules['selector-pseudo-element-case'] = null;
|
|
22
|
+
lintConfig.rules['string-quotes'] = null;
|
|
23
|
+
lintConfig.rules['unit-case'] = null;
|
|
24
|
+
lintConfig.rules['indentation'] = null;
|
|
25
|
+
|
|
8
26
|
// node-sass can't handle modern color function notation
|
|
9
27
|
lintConfig.rules['color-function-notation'] = null;
|
|
10
28
|
|
package/generators/app/templates/tests/backstop/engine_scripts/playwright/clickAndHoverHelper.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module.exports = async (page, scenario) => {
|
|
2
|
+
const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector;
|
|
3
|
+
const clickSelector = scenario.clickSelectors || scenario.clickSelector;
|
|
4
|
+
const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector;
|
|
5
|
+
const scrollToSelector = scenario.scrollToSelector;
|
|
6
|
+
const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int]
|
|
7
|
+
|
|
8
|
+
if (keyPressSelector) {
|
|
9
|
+
for (const keyPressSelectorItem of [].concat(keyPressSelector)) {
|
|
10
|
+
await page.waitForSelector(keyPressSelectorItem.selector);
|
|
11
|
+
await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (hoverSelector) {
|
|
16
|
+
for (const hoverSelectorIndex of [].concat(hoverSelector)) {
|
|
17
|
+
await page.waitForSelector(hoverSelectorIndex);
|
|
18
|
+
await page.hover(hoverSelectorIndex);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (clickSelector) {
|
|
23
|
+
for (const clickSelectorIndex of [].concat(clickSelector)) {
|
|
24
|
+
await page.waitForSelector(clickSelectorIndex);
|
|
25
|
+
await page.click(clickSelectorIndex);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (postInteractionWait) {
|
|
30
|
+
if (parseInt(postInteractionWait) > 0) {
|
|
31
|
+
await page.waitForTimeout(postInteractionWait);
|
|
32
|
+
} else {
|
|
33
|
+
await page.waitForSelector(postInteractionWait);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (scrollToSelector) {
|
|
38
|
+
await page.waitForSelector(scrollToSelector);
|
|
39
|
+
await page.evaluate((scrollToSelector) => {
|
|
40
|
+
document.querySelector(scrollToSelector).scrollIntoView();
|
|
41
|
+
}, scrollToSelector);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* INTERCEPT IMAGES
|
|
3
|
+
* Listen to all requests. If a request matches IMAGE_URL_RE
|
|
4
|
+
* then stub the image with data from IMAGE_STUB_URL
|
|
5
|
+
*
|
|
6
|
+
* Use this in an onBefore script E.G.
|
|
7
|
+
```
|
|
8
|
+
module.exports = async function(page, scenario) {
|
|
9
|
+
require('./interceptImages')(page, scenario);
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const IMAGE_URL_RE = /\.gif|\.jpg|\.png/i;
|
|
19
|
+
const IMAGE_STUB_URL = path.resolve(__dirname, '../../imageStub.jpg');
|
|
20
|
+
const IMAGE_DATA_BUFFER = fs.readFileSync(IMAGE_STUB_URL);
|
|
21
|
+
const HEADERS_STUB = {};
|
|
22
|
+
|
|
23
|
+
module.exports = async function (page, scenario) {
|
|
24
|
+
page.route(IMAGE_URL_RE, (route) => {
|
|
25
|
+
route.fulfill({
|
|
26
|
+
body: IMAGE_DATA_BUFFER,
|
|
27
|
+
headers: HEADERS_STUB,
|
|
28
|
+
status: 200,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
module.exports = async (browserContext, scenario) => {
|
|
4
|
+
let cookies = [];
|
|
5
|
+
const cookiePath = scenario.cookiePath;
|
|
6
|
+
|
|
7
|
+
// Read Cookies from File, if exists
|
|
8
|
+
if (fs.existsSync(cookiePath)) {
|
|
9
|
+
cookies = JSON.parse(fs.readFileSync(cookiePath));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Add cookies to browser
|
|
13
|
+
browserContext.addCookies(cookies);
|
|
14
|
+
|
|
15
|
+
console.log('Cookie state restored with:', JSON.stringify(cookies, null, 2));
|
|
16
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OVERRIDE CSS
|
|
3
|
+
* Apply this CSS to the loaded page, as a way to override styles.
|
|
4
|
+
*
|
|
5
|
+
* Use this in an onReady script E.G.
|
|
6
|
+
```
|
|
7
|
+
module.exports = async function(page, scenario) {
|
|
8
|
+
await require('./overrideCSS')(page, scenario);
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const BACKSTOP_TEST_CSS_OVERRIDE = `
|
|
15
|
+
html {
|
|
16
|
+
background-image: none;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
module.exports = async (page, scenario) => {
|
|
21
|
+
// inject arbitrary css to override styles
|
|
22
|
+
await page.addStyleTag({
|
|
23
|
+
content: BACKSTOP_TEST_CSS_OVERRIDE,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
console.log('BACKSTOP_TEST_CSS_OVERRIDE injected for: ' + scenario.label);
|
|
27
|
+
};
|
package/generators/app/templates/tests/backstop/engine_scripts/puppet/clickAndHoverHelper.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
module.exports = async (page, scenario) => {
|
|
2
|
-
const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector;
|
|
3
|
-
const clickSelector = scenario.clickSelectors || scenario.clickSelector;
|
|
4
|
-
const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector;
|
|
5
|
-
const scrollToSelector = scenario.scrollToSelector;
|
|
6
|
-
const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int]
|
|
7
|
-
|
|
8
|
-
if (keyPressSelector) {
|
|
9
|
-
for (const keyPressSelectorItem of [].concat(keyPressSelector)) {
|
|
10
|
-
await page.
|
|
11
|
-
await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (hoverSelector) {
|
|
16
|
-
for (const hoverSelectorIndex of [].concat(hoverSelector)) {
|
|
17
|
-
await page.
|
|
18
|
-
await page.hover(hoverSelectorIndex);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (clickSelector) {
|
|
23
|
-
for (const clickSelectorIndex of [].concat(clickSelector)) {
|
|
24
|
-
await page.
|
|
25
|
-
await page.click(clickSelectorIndex);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (postInteractionWait) {
|
|
30
|
-
await page.
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (scrollToSelector) {
|
|
34
|
-
await page.
|
|
35
|
-
await page.evaluate((scrollToSelector) => {
|
|
36
|
-
document.querySelector(scrollToSelector).scrollIntoView();
|
|
37
|
-
}, scrollToSelector);
|
|
38
|
-
}
|
|
39
|
-
};
|
|
1
|
+
module.exports = async (page, scenario) => {
|
|
2
|
+
const hoverSelector = scenario.hoverSelectors || scenario.hoverSelector;
|
|
3
|
+
const clickSelector = scenario.clickSelectors || scenario.clickSelector;
|
|
4
|
+
const keyPressSelector = scenario.keyPressSelectors || scenario.keyPressSelector;
|
|
5
|
+
const scrollToSelector = scenario.scrollToSelector;
|
|
6
|
+
const postInteractionWait = scenario.postInteractionWait; // selector [str] | ms [int]
|
|
7
|
+
|
|
8
|
+
if (keyPressSelector) {
|
|
9
|
+
for (const keyPressSelectorItem of [].concat(keyPressSelector)) {
|
|
10
|
+
await page.waitForSelector(keyPressSelectorItem.selector);
|
|
11
|
+
await page.type(keyPressSelectorItem.selector, keyPressSelectorItem.keyPress);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (hoverSelector) {
|
|
16
|
+
for (const hoverSelectorIndex of [].concat(hoverSelector)) {
|
|
17
|
+
await page.waitForSelector(hoverSelectorIndex);
|
|
18
|
+
await page.hover(hoverSelectorIndex);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (clickSelector) {
|
|
23
|
+
for (const clickSelectorIndex of [].concat(clickSelector)) {
|
|
24
|
+
await page.waitForSelector(clickSelectorIndex);
|
|
25
|
+
await page.click(clickSelectorIndex);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (postInteractionWait) {
|
|
30
|
+
await page.waitForTimeout(postInteractionWait);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (scrollToSelector) {
|
|
34
|
+
await page.waitForSelector(scrollToSelector);
|
|
35
|
+
await page.evaluate((scrollToSelector) => {
|
|
36
|
+
document.querySelector(scrollToSelector).scrollIntoView();
|
|
37
|
+
}, scrollToSelector);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
@@ -36,7 +36,7 @@ module.exports = async function (page, scenario) {
|
|
|
36
36
|
const cookies = cookiesList.map((cookie) => `${cookie.name}=${cookie.value}`).join('; ');
|
|
37
37
|
const headers = Object.assign(request.headers(), { cookie: cookies });
|
|
38
38
|
const options = {
|
|
39
|
-
headers
|
|
39
|
+
headers,
|
|
40
40
|
body: request.postData(),
|
|
41
41
|
method: request.method(),
|
|
42
42
|
follow: 20,
|
|
@@ -19,5 +19,5 @@ Use following npm scripts for your test workflow:
|
|
|
19
19
|
|
|
20
20
|
- `npm run visual-test` runs the tests, compares the results against the reference screenshots
|
|
21
21
|
and generates a report under '/public/reports/backstop/html/'
|
|
22
|
-
|
|
22
|
+
(use this also for creating new reference screenshots, ignore the failed tests and approve with `npm run visual-approve`)
|
|
23
23
|
- `npm run visual-approve` updates the references with results from last test
|
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
/// <reference types="cypress" />
|
|
2
2
|
|
|
3
|
+
const page404Url = '/404';
|
|
4
|
+
const nonExistingUrl = '/pagenotfound';
|
|
5
|
+
|
|
3
6
|
// test 404 page
|
|
4
7
|
context('404 Page Test', () => {
|
|
5
8
|
beforeEach(() => {
|
|
6
|
-
cy.visit(
|
|
9
|
+
cy.visit(page404Url);
|
|
7
10
|
});
|
|
8
11
|
|
|
9
12
|
describe('HTML Head', () => {
|
|
10
|
-
it('
|
|
13
|
+
it('Character encoding is UTF-8', () => {
|
|
11
14
|
cy.document().should('have.property', 'charset').and('eq', 'UTF-8');
|
|
12
15
|
});
|
|
13
16
|
|
|
14
|
-
it('
|
|
17
|
+
it('Title includes 404', () => {
|
|
15
18
|
cy.title().should('include', '404');
|
|
16
19
|
});
|
|
17
20
|
});
|
|
18
21
|
|
|
19
22
|
describe('Root DOM node', () => {
|
|
20
|
-
it('
|
|
23
|
+
it('Has lang attribute', () => {
|
|
21
24
|
cy.root().should('match', 'html').and('have.attr', 'lang', 'en');
|
|
22
25
|
});
|
|
23
26
|
});
|
|
24
27
|
|
|
25
28
|
describe('Status Code', () => {
|
|
26
|
-
it('
|
|
29
|
+
it('Should be 404 for a non existing page', () => {
|
|
27
30
|
cy.request({
|
|
28
|
-
url:
|
|
31
|
+
url: nonExistingUrl,
|
|
29
32
|
failOnStatusCode: false,
|
|
30
33
|
}).then((response) => {
|
|
31
34
|
expect(response.status).to.eq(404);
|
|
@@ -7,11 +7,11 @@ context('Index Page Test', () => {
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
describe('Location', () => {
|
|
10
|
-
it('
|
|
10
|
+
it('Has no hash', () => {
|
|
11
11
|
cy.hash().should('be.empty');
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it('
|
|
14
|
+
it('Passes window.location tests', () => {
|
|
15
15
|
const baseUrl = Cypress.config().baseUrl;
|
|
16
16
|
|
|
17
17
|
cy.location().should((location) => {
|
|
@@ -25,17 +25,17 @@ context('Index Page Test', () => {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
describe('HTML Head', () => {
|
|
28
|
-
it('
|
|
28
|
+
it('Character encoding is UTF-8', () => {
|
|
29
29
|
cy.document().should('have.property', 'charset').and('eq', 'UTF-8');
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('Title includes index page', () => {
|
|
33
33
|
cy.title().should('include', 'index page');
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
describe('Root DOM node', () => {
|
|
38
|
-
it('
|
|
38
|
+
it('Has correct lang attribute', () => {
|
|
39
39
|
cy.root().should('match', 'html').and('have.attr', 'lang', 'en');
|
|
40
40
|
});
|
|
41
41
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Cypress e2e Tests
|
|
2
2
|
|
|
3
|
-
End
|
|
3
|
+
End-to-end testing with cypress.
|
|
4
4
|
|
|
5
5
|
[More about cypress](https://www.npmjs.com/package/cypress)
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@ We use the [default configuration](https://docs.cypress.io/guides/core-concepts/
|
|
|
16
16
|
Use following npm scripts for your test workflow:
|
|
17
17
|
|
|
18
18
|
- `npm run cypress-test` to run full cypress test suite (use this to set up your tests)
|
|
19
|
-
- `npm
|
|
19
|
+
- `npm test` cypress tests are run in the test chain
|
|
20
20
|
|
|
21
21
|
## CI setup
|
|
22
22
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
const page404Url = '/404';
|
|
4
|
+
const nonExistingUrl = '/pagenotfound';
|
|
5
|
+
|
|
6
|
+
test.describe('404 Page', () => {
|
|
7
|
+
test.beforeEach(async ({ page }) => {
|
|
8
|
+
await page.goto(page404Url);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test.describe('HTML Head', () => {
|
|
12
|
+
test('character encoding is UTF-8', async ({ page }) => {
|
|
13
|
+
const charset = await page.evaluate(() => window.document.characterSet);
|
|
14
|
+
expect(charset).toEqual('UTF-8');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Title includes 404', async ({ page }) => {
|
|
18
|
+
await expect(page).toHaveTitle(/404/);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test.describe('Root DOM node', () => {
|
|
23
|
+
test('Has correct lang attribute', async ({ page }) => {
|
|
24
|
+
const lang = await page.locator('html').getAttribute('lang');
|
|
25
|
+
expect(lang).toEqual('en');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test.describe('404 Page', () => {
|
|
31
|
+
test.describe('Status Code', () => {
|
|
32
|
+
test('Should be 404 for a non existing page', async ({ page }) => {
|
|
33
|
+
page.on('response', (response) => {
|
|
34
|
+
if (response.url().includes(nonExistingUrl)) {
|
|
35
|
+
expect(response.status()).toBe(404);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
await page.goto(nonExistingUrl);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
test.describe('Index Page', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/index');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
test.describe('Location', () => {
|
|
9
|
+
test('Has no hash', async ({ page }) => {
|
|
10
|
+
expect(page.url().includes('#')).toBeFalsy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('Passes window.location tests', async ({ page }, testInfo) => {
|
|
14
|
+
const baseUrl = testInfo.project.use.baseURL;
|
|
15
|
+
const location = await page.evaluate(() => window.location);
|
|
16
|
+
|
|
17
|
+
expect(location.hash).toEqual('');
|
|
18
|
+
expect(location.href).toEqual(`${baseUrl}/index`);
|
|
19
|
+
expect(location.origin).toEqual(`${baseUrl}`);
|
|
20
|
+
expect(location.pathname).toEqual('/index');
|
|
21
|
+
expect(location.search).toEqual('');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test.describe('HTML Head', () => {
|
|
26
|
+
test('Character encoding is UTF-8', async ({ page }) => {
|
|
27
|
+
const charset = await page.evaluate(() => window.document.characterSet);
|
|
28
|
+
expect(charset).toEqual('UTF-8');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('Title includes index page', async ({ page }) => {
|
|
32
|
+
await expect(page).toHaveTitle(/index page/);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test.describe('Root DOM node', () => {
|
|
37
|
+
test('Has correct lang attribute', async ({ page }) => {
|
|
38
|
+
const lang = await page.locator('html').getAttribute('lang');
|
|
39
|
+
expect(lang).toEqual('en');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
const port = process.env.PORT || 8080;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* See https://playwright.dev/docs/test-configuration
|
|
7
|
+
*/
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
testDir: './e2e',
|
|
10
|
+
/* Maximum time one test can run for. */
|
|
11
|
+
timeout: 30 * 1000,
|
|
12
|
+
expect: {
|
|
13
|
+
/**
|
|
14
|
+
* Maximum time expect() should wait for the condition to be met.
|
|
15
|
+
* For example in `await expect(locator).toHaveText();`
|
|
16
|
+
*/
|
|
17
|
+
timeout: 5000,
|
|
18
|
+
},
|
|
19
|
+
/* Run tests in files in parallel */
|
|
20
|
+
fullyParallel: true,
|
|
21
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
22
|
+
forbidOnly: !!process.env.CI,
|
|
23
|
+
/* Retry on CI only */
|
|
24
|
+
retries: process.env.CI ? 2 : 0,
|
|
25
|
+
/* Opt out of parallel tests on CI. */
|
|
26
|
+
workers: process.env.CI ? 1 : undefined,
|
|
27
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
28
|
+
reporter: process.env.CI
|
|
29
|
+
? [
|
|
30
|
+
['dot'],
|
|
31
|
+
[
|
|
32
|
+
'html',
|
|
33
|
+
{
|
|
34
|
+
open: 'never',
|
|
35
|
+
outputFolder: '../../public/reports/playwright',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
]
|
|
39
|
+
: [
|
|
40
|
+
['list'],
|
|
41
|
+
[
|
|
42
|
+
'html',
|
|
43
|
+
{
|
|
44
|
+
open: 'on-failure',
|
|
45
|
+
outputFolder: '../../public/reports/playwright',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
],
|
|
49
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
50
|
+
use: {
|
|
51
|
+
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
|
|
52
|
+
actionTimeout: 0,
|
|
53
|
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
54
|
+
baseURL: `http://localhost:${port}`,
|
|
55
|
+
/* Capture screenshot. Defaults to 'off' */
|
|
56
|
+
screenshot: 'only-on-failure',
|
|
57
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
58
|
+
trace: 'on-first-retry',
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/* Configure projects for major browsers */
|
|
62
|
+
projects: [
|
|
63
|
+
{
|
|
64
|
+
name: 'chromium',
|
|
65
|
+
use: { ...devices['Desktop Chrome'] },
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// {
|
|
69
|
+
// name: 'firefox',
|
|
70
|
+
// use: { ...devices['Desktop Firefox'] },
|
|
71
|
+
// },
|
|
72
|
+
|
|
73
|
+
// {
|
|
74
|
+
// name: 'webkit',
|
|
75
|
+
// use: { ...devices['Desktop Safari'] },
|
|
76
|
+
// },
|
|
77
|
+
|
|
78
|
+
/* Test against mobile viewports. */
|
|
79
|
+
// {
|
|
80
|
+
// name: 'Mobile Chrome',
|
|
81
|
+
// use: { ...devices['Pixel 5'] },
|
|
82
|
+
// },
|
|
83
|
+
// {
|
|
84
|
+
// name: 'Mobile Safari',
|
|
85
|
+
// use: { ...devices['iPhone 12'] },
|
|
86
|
+
// },
|
|
87
|
+
|
|
88
|
+
/* Test against branded browsers. */
|
|
89
|
+
// {
|
|
90
|
+
// name: 'Microsoft Edge',
|
|
91
|
+
// use: { channel: 'msedge' },
|
|
92
|
+
// },
|
|
93
|
+
// {
|
|
94
|
+
// name: 'Google Chrome',
|
|
95
|
+
// use: { channel: 'chrome' },
|
|
96
|
+
// },
|
|
97
|
+
],
|
|
98
|
+
|
|
99
|
+
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
|
|
100
|
+
outputDir: 'test-results/',
|
|
101
|
+
|
|
102
|
+
/* Run your local dev server before starting the tests */
|
|
103
|
+
webServer: {
|
|
104
|
+
command: 'npm run prod:serve',
|
|
105
|
+
port: Number(port),
|
|
106
|
+
reuseExistingServer: true,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Playwright e2e Tests
|
|
2
|
+
|
|
3
|
+
End-to-end testing with playwright.
|
|
4
|
+
|
|
5
|
+
[More about playwright](https://playwright.dev/)
|
|
6
|
+
|
|
7
|
+
## Directories
|
|
8
|
+
|
|
9
|
+
- `./e2e` is the place for your tests (you may create subfolders as well)
|
|
10
|
+
|
|
11
|
+
## Scripts
|
|
12
|
+
|
|
13
|
+
Use following npm scripts for your test workflow:
|
|
14
|
+
|
|
15
|
+
- `npm run playwright-test` to run playwright ui-mode (use this to set up your tests)
|
|
16
|
+
- `npm test` playwright tests run in the test chain (this also works well in ci environments)
|
|
17
|
+
|
|
18
|
+
or [run and generate playwright tests directly in VS Code](https://playwright.dev/docs/codegen#generate-tests-in-vs-code)
|
|
19
|
+
|
|
20
|
+
## CI setup
|
|
21
|
+
|
|
22
|
+
Add `CI=true` as environment variable.
|
|
23
|
+
|
|
24
|
+
More on [configuation for continous integration](https://playwright.dev/docs/ci)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "generator-nitro",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0",
|
|
4
4
|
"description": "Yeoman generator for the nitro frontend framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "merkle-open/generator-nitro",
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@merkle-open/eslint-config": "1.0.0",
|
|
48
|
-
"ejs": "3.1.
|
|
48
|
+
"ejs": "3.1.9",
|
|
49
49
|
"eslint": "7.32.0",
|
|
50
50
|
"eslint-plugin-import": "2.27.5",
|
|
51
|
-
"fs-extra": "11.1.
|
|
52
|
-
"jasmine": "4.
|
|
51
|
+
"fs-extra": "11.1.1",
|
|
52
|
+
"jasmine": "4.6.0",
|
|
53
53
|
"yeoman-assert": "3.1.1",
|
|
54
54
|
"yeoman-test": "6.3.0"
|
|
55
55
|
}
|