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.
Files changed (35) hide show
  1. package/generators/app/templates/.node-version +1 -1
  2. package/generators/app/templates/.prettierignore +1 -0
  3. package/generators/app/templates/CUTAWAY.gitignore +3 -1
  4. package/generators/app/templates/CUTAWAYpackage.json +34 -29
  5. package/generators/app/templates/config/default.js +0 -6
  6. package/generators/app/templates/config/webpack/options.js +2 -5
  7. package/generators/app/templates/project/docs/nitro-config.md +0 -16
  8. package/generators/app/templates/project/docs/nitro.md +1 -1
  9. package/generators/app/templates/src/patterns/atoms/box/css/modifier/box-dark.scss +0 -1
  10. package/generators/app/templates/src/patterns/atoms/stage/css/stage.scss +7 -6
  11. package/generators/app/templates/src/patterns/molecules/example/css/modifier/example-blue.scss +10 -3
  12. package/generators/app/templates/src/shared/base/grid/css/variables/grid.scss +2 -2
  13. package/generators/app/templates/src/shared/base/webfonts/css/webfont-gaegu.scss +6 -15
  14. package/generators/app/templates/src/shared/base/webfonts/css/webfont-playfair-display.scss +12 -20
  15. package/generators/app/templates/src/shared/utils/fixed-aspect-ratio/css/fixed-aspect-ratio.scss +4 -6
  16. package/generators/app/templates/src/shared/utils/typo/css/typo.scss +19 -16
  17. package/generators/app/templates/src/shared/utils/z-index/css/z-index.scss +1 -0
  18. package/generators/app/templates/stylelint.config.js +18 -0
  19. package/generators/app/templates/tests/backstop/engine_scripts/playwright/clickAndHoverHelper.js +43 -0
  20. package/generators/app/templates/tests/backstop/engine_scripts/playwright/interceptImages.js +31 -0
  21. package/generators/app/templates/tests/backstop/engine_scripts/playwright/loadCookies.js +16 -0
  22. package/generators/app/templates/tests/backstop/engine_scripts/playwright/onBefore.js +3 -0
  23. package/generators/app/templates/tests/backstop/engine_scripts/playwright/onReady.js +6 -0
  24. package/generators/app/templates/tests/backstop/engine_scripts/playwright/overrideCSS.js +27 -0
  25. package/generators/app/templates/tests/backstop/engine_scripts/puppet/clickAndHoverHelper.js +39 -39
  26. package/generators/app/templates/tests/backstop/engine_scripts/puppet/ignoreCSP.js +1 -1
  27. package/generators/app/templates/tests/backstop/readme.md +1 -1
  28. package/generators/app/templates/tests/cypress/cypress/e2e/pages/404.cy.js +9 -6
  29. package/generators/app/templates/tests/cypress/cypress/e2e/pages/index.cy.js +5 -5
  30. package/generators/app/templates/tests/cypress/readme.md +2 -2
  31. package/generators/app/templates/tests/playwright/e2e/pages/404.spec.ts +41 -0
  32. package/generators/app/templates/tests/playwright/e2e/pages/index.spec.ts +42 -0
  33. package/generators/app/templates/tests/playwright/playwright.config.ts +108 -0
  34. package/generators/app/templates/tests/playwright/readme.md +24 -0
  35. package/package.json +4 -4
@@ -1 +1 @@
1
- 18.15.0
1
+ 18.16.0
@@ -22,3 +22,4 @@
22
22
 
23
23
  # Project
24
24
  **/export
25
+ src/shared/base/reset/css/yui/reset.css
@@ -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
- "node": ">=14.15.0 <19",
10
- "npm": ">=6.14.8 <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 test:cypress:serve cypress-test:open",
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=8890 NITRO_MODE=test npm-run-all --parallel --race lighthouse-test:*",
29
- "lighthouse-test:serve": "npm run prod:serve",
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
- "prettier": "prettier --write \"**/*.*(js|jsx|ts|tsx|json|md|mdx|graphql|gql|yml|yaml)\"",
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:cypress": "npm run build && cross-env PORT=8888 NITRO_MODE=test npm-run-all --parallel --race test:cypress:*",
41
- "test:cypress:serve": "npm run prod:serve",
42
- "test:cypress:test": "cypress run --project ./tests/cypress/",
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=8889 npm-run-all --parallel --race visual-test:*",
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.29.0"<% if (options.exampleCode) { %>,
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.10.2",
93
- "prevent-window-opener-attacks": "0.3.0"<% } %><% if (options.jsCompiler === 'js') { %>,
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.19.1",<% } %>
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.1",
103
- "@merkle-open/stylelint-config": "1.0.0",
104
- "@merkle-open/ts-config": "1.0.1",
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 %>",<% if (options.jsCompiler === 'ts') { %>
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.4",
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.7.0",
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.0.2",
130
- "lint-staged": "13.2.0",<% if (options.themes) { %>
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.7.12",
136
+ "npm-check-updates": "16.10.9",
133
137
  "npm-run-all": "4.1.5",
134
- "prettier": "2.8.4",
135
- "rimraf": "4.4.0",
136
- "stylelint": "14.16.1",<% if (options.jsCompiler === 'ts') { %>
137
- "typescript": "4.9.5",<% } %>
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)<% } %>
@@ -1,7 +1,6 @@
1
1
  @import '../../../../../shared/utils/colors2/css/colors2';
2
2
 
3
3
  .a-box--dark {
4
-
5
4
  color: $color-gray-9;
6
5
  background-color: $color-gray-3;
7
6
 
@@ -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 { background-position: 10vw 600px, 50% 200px, 70% -170px, 0 0; }
22
- to { background-position: 20vw -200px, 120% -100px, 30% 300px, 100% 0; }
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
  }
@@ -7,7 +7,14 @@
7
7
  }
8
8
 
9
9
  @keyframes blue-background-change {
10
- 0%,100% { background-color: darken(desaturate($color-brand-1, 30%), 10%); }
11
- 30% { background-color: darken($color-brand-1, 20%); }
12
- 60% { background-color: darken($color-brand-1, 10%); }
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
- local('Gaegu Light'),
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
- local('Gaegu Regular'),
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
- local('Gaegu Bold'),
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
- local('Playfair Display Regular'),
9
- local('PlayfairDisplay-Regular'),
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
- local('Playfair Display Italic'),
22
- local('PlayfairDisplay-Italic'),
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
- local('Playfair Display Bold'),
35
- local('PlayfairDisplay-Bold'),
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
- local('Playfair Display Black'),
48
- local('PlayfairDisplay-Black'),
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
  }
@@ -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
- #{$child} { // stylelint-disable-line
13
- bottom: 0;
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
- right: 0;
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($all-font-definition, map-get(map-get($typography-definitions, $font-bundle), $viewport));
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
 
@@ -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,3 @@
1
+ module.exports = async (page, scenario, viewport, isReference, browserContext) => {
2
+ await require('./loadCookies')(browserContext, scenario);
3
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = async (page, scenario, viewport, isReference, browserContext) => {
2
+ console.log('SCENARIO > ' + scenario.label);
3
+ await require('./clickAndHoverHelper')(page, scenario);
4
+
5
+ // add more ready handlers here...
6
+ };
@@ -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
+ };
@@ -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.waitFor(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.waitFor(hoverSelectorIndex);
18
- await page.hover(hoverSelectorIndex);
19
- }
20
- }
21
-
22
- if (clickSelector) {
23
- for (const clickSelectorIndex of [].concat(clickSelector)) {
24
- await page.waitFor(clickSelectorIndex);
25
- await page.click(clickSelectorIndex);
26
- }
27
- }
28
-
29
- if (postInteractionWait) {
30
- await page.waitFor(postInteractionWait);
31
- }
32
-
33
- if (scrollToSelector) {
34
- await page.waitFor(scrollToSelector);
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: 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
- - use this also for creating new reference screenshots, ignore the failed tests and approve with npm script `npm run visual-approve`)
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('/404');
9
+ cy.visit(page404Url);
7
10
  });
8
11
 
9
12
  describe('HTML Head', () => {
10
- it('charset meta tag is UTF-8', () => {
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('title includes 404', () => {
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('has lang attribute', () => {
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('should be 404 for a non existing page', () => {
29
+ it('Should be 404 for a non existing page', () => {
27
30
  cy.request({
28
- url: '/pagenotfound',
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('has no hash', () => {
10
+ it('Has no hash', () => {
11
11
  cy.hash().should('be.empty');
12
12
  });
13
13
 
14
- it('passes window.location tests', () => {
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('charset meta tag is UTF-8', () => {
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('title includes index page', () => {
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('has lang attribute', () => {
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 to end testing with cypress.
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 run test:cypress` to run cypress tests in headless mode (use this for ci)
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.0",
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.8",
48
+ "ejs": "3.1.9",
49
49
  "eslint": "7.32.0",
50
50
  "eslint-plugin-import": "2.27.5",
51
- "fs-extra": "11.1.0",
52
- "jasmine": "4.5.0",
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
  }