Merge pull request #6314 from LLK/release/2021-11-17

[Master] release/2021-11-17
This commit is contained in:
Eric Rosenbaum 2021-11-18 11:24:44 -05:00 committed by GitHub
commit 27bdbf0286
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 709 additions and 1141 deletions

View file

@ -1,5 +1,6 @@
{ {
"plugins": [ "plugins": [
"transform-async-to-generator",
"transform-object-rest-spread", "transform-object-rest-spread",
"transform-require-context", "transform-require-context",
"syntax-dynamic-import" "syntax-dynamic-import"

View file

@ -100,21 +100,7 @@ aliases:
- run: - run:
name: "integration tests with Jest" name: "integration tests with Jest"
command: | command: |
JEST_JUNIT_OUTPUT_NAME=integration-jest-results.xml npm run test:integration:jest:remote -- --reporters=jest-junit JEST_JUNIT_OUTPUT_NAME=integration-jest-results.xml npm run test:integration:remote -- --reporters=jest-junit
- store_test_results:
path: test/results
- &integration_tap
<<: *defaults
steps:
- *restore_git_cache
- checkout
- *restore_npm_cache
- run:
name: "integration tests with Tap"
command: |
mkdir ./test/results
npm run test:smoke:sauce -- --output-file ./test/results/integration-raw-tap.tap
npm run test:smoke:convertReportToXunit
- store_test_results: - store_test_results:
path: test/results path: test/results
- &update-translations - &update-translations
@ -139,12 +125,8 @@ jobs:
<<: *deploy <<: *deploy
integration-staging-jest: integration-staging-jest:
<<: *integration_jest <<: *integration_jest
integration-staging-tap:
<<: *integration_tap
integration-production-jest: integration-production-jest:
<<: *integration_jest <<: *integration_jest
integration-production-tap:
<<: *integration_tap
update-translations: update-translations:
<<: *update-translations <<: *update-translations
@ -201,18 +183,6 @@ workflows:
- develop - develop
- /^hotfix\/.*/ - /^hotfix\/.*/
- /^release\/.*/ - /^release\/.*/
- integration-staging-tap:
context:
- scratch-www-all
- scratch-www-staging
requires:
- deploy-staging
filters:
branches:
only:
- develop
- /^hotfix\/.*/
- /^release\/.*/
- integration-production-jest: - integration-production-jest:
context: context:
- scratch-www-all - scratch-www-all
@ -223,16 +193,6 @@ workflows:
branches: branches:
only: only:
- master - master
- integration-production-tap:
context:
- scratch-www-all
- scratch-www-production
requires:
- deploy-production
filters:
branches:
only:
- master
Update-translations: Update-translations:
triggers: triggers:
- schedule: # every evening at 7pm EST (8pm EDT, Midnight UTC) - schedule: # every evening at 7pm EST (8pm EDT, Midnight UTC)

240
package-lock.json generated
View file

@ -308,9 +308,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.16.2", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz",
"integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
@ -325,9 +325,9 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz",
"integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.16.0", "@babel/code-frame": "^7.16.0",
@ -335,7 +335,7 @@
"@babel/helper-function-name": "^7.16.0", "@babel/helper-function-name": "^7.16.0",
"@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0",
"@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0",
"@babel/parser": "^7.16.0", "@babel/parser": "^7.16.3",
"@babel/types": "^7.16.0", "@babel/types": "^7.16.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
@ -479,40 +479,40 @@
} }
}, },
"@babel/helper-compilation-targets": { "@babel/helper-compilation-targets": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz",
"integrity": "sha512-S7iaOT1SYlqK0sQaCi21RX4+13hmdmnxIEAnQUB/eh7GeAnRjOUgTYpLkUOiRXzD+yog1JxP0qyAQZ7ZxVxLVg==", "integrity": "sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/compat-data": "^7.16.0", "@babel/compat-data": "^7.16.0",
"@babel/helper-validator-option": "^7.14.5", "@babel/helper-validator-option": "^7.14.5",
"browserslist": "^4.16.6", "browserslist": "^4.17.5",
"semver": "^6.3.0" "semver": "^6.3.0"
}, },
"dependencies": { "dependencies": {
"browserslist": { "browserslist": {
"version": "4.17.6", "version": "4.18.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
"integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"caniuse-lite": "^1.0.30001274", "caniuse-lite": "^1.0.30001280",
"electron-to-chromium": "^1.3.886", "electron-to-chromium": "^1.3.896",
"escalade": "^3.1.1", "escalade": "^3.1.1",
"node-releases": "^2.0.1", "node-releases": "^2.0.1",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001274", "version": "1.0.30001280",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001274.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001280.tgz",
"integrity": "sha512-+Nkvv0fHyhISkiMIjnyjmf5YJcQ1IQHZN6U9TLUMroWR38FNwpsC51Gb68yueafX1V6ifOisInSgP9WJFS13ew==", "integrity": "sha512-kFXwYvHe5rix25uwueBxC569o53J6TpnGu0BEEn+6Lhl2vsnAumRFWEBhDft1fwyo6m1r4i+RqA4+163FpeFcA==",
"dev": true "dev": true
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.887", "version": "1.3.898",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.887.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.898.tgz",
"integrity": "sha512-QQUumrEjFDKSVYVdaeBmFdyQGoaV+fCSMyWHvfx/u22bRHSTeBQYt6P4jMY+gFd4kgKB9nqk7RMtWkDB49OYPA==", "integrity": "sha512-dxEsaHy9Ter268LO7P8uWomuChbyML4zZk5F9+UZSozFRS7ggC5cQ8fPIM8Pec+6uWGdujuDagQhIbqjohUK2w==",
"dev": true "dev": true
}, },
"picocolors": { "picocolors": {
@ -707,9 +707,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.16.2", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz",
"integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
@ -724,9 +724,9 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz",
"integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.16.0", "@babel/code-frame": "^7.16.0",
@ -734,7 +734,7 @@
"@babel/helper-function-name": "^7.16.0", "@babel/helper-function-name": "^7.16.0",
"@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0",
"@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0",
"@babel/parser": "^7.16.0", "@babel/parser": "^7.16.3",
"@babel/types": "^7.16.0", "@babel/types": "^7.16.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
@ -926,9 +926,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.16.2", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz",
"integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
@ -943,9 +943,9 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz",
"integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.16.0", "@babel/code-frame": "^7.16.0",
@ -953,7 +953,7 @@
"@babel/helper-function-name": "^7.16.0", "@babel/helper-function-name": "^7.16.0",
"@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0",
"@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0",
"@babel/parser": "^7.16.0", "@babel/parser": "^7.16.3",
"@babel/types": "^7.16.0", "@babel/types": "^7.16.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
@ -1088,13 +1088,13 @@
"dev": true "dev": true
}, },
"@babel/helpers": { "@babel/helpers": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.3.tgz",
"integrity": "sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ==", "integrity": "sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/template": "^7.16.0", "@babel/template": "^7.16.0",
"@babel/traverse": "^7.16.0", "@babel/traverse": "^7.16.3",
"@babel/types": "^7.16.0" "@babel/types": "^7.16.0"
}, },
"dependencies": { "dependencies": {
@ -1159,9 +1159,9 @@
} }
}, },
"@babel/parser": { "@babel/parser": {
"version": "7.16.2", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz",
"integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==",
"dev": true "dev": true
}, },
"@babel/template": { "@babel/template": {
@ -1176,9 +1176,9 @@
} }
}, },
"@babel/traverse": { "@babel/traverse": {
"version": "7.16.0", "version": "7.16.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.0.tgz", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz",
"integrity": "sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==", "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/code-frame": "^7.16.0", "@babel/code-frame": "^7.16.0",
@ -1186,7 +1186,7 @@
"@babel/helper-function-name": "^7.16.0", "@babel/helper-function-name": "^7.16.0",
"@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0",
"@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0",
"@babel/parser": "^7.16.0", "@babel/parser": "^7.16.3",
"@babel/types": "^7.16.0", "@babel/types": "^7.16.0",
"debug": "^4.1.0", "debug": "^4.1.0",
"globals": "^11.1.0" "globals": "^11.1.0"
@ -1483,24 +1483,16 @@
} }
}, },
"@formatjs/intl-pluralrules": { "@formatjs/intl-pluralrules": {
"version": "4.0.28", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/@formatjs/intl-pluralrules/-/intl-pluralrules-4.0.28.tgz", "resolved": "https://registry.npmjs.org/@formatjs/intl-pluralrules/-/intl-pluralrules-4.1.0.tgz",
"integrity": "sha512-sWtOHwEff6/cHuSk5l6zpcB3POPCYlBx3DUGASb7QU6AD/tO/oKW6oRHOCHbBdspkBEsUJByZ9LlP2r0Xw6yPQ==", "integrity": "sha512-rJFWETXa1OOcru4kqjEz/MUyBxdcMWhbmqKVjDBVZ6HF4ZqkC1TUWQkj+jqIxDiShQ6/J7QLMOGMwiGDjGepHg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@formatjs/ecma402-abstract": "1.9.4", "@formatjs/ecma402-abstract": "1.9.5",
"@formatjs/intl-localematcher": "0.2.18",
"tslib": "^2.1.0" "tslib": "^2.1.0"
}, },
"dependencies": { "dependencies": {
"@formatjs/ecma402-abstract": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.9.4.tgz",
"integrity": "sha512-ePJXI7tWC9PBxQxS7jtbkCLGVmpC8MH8n9Yjmg8dsh9wXK9svu7nAbq76Oiu5Zb+5GVkLkeTVerlSvHCbNImlA==",
"dev": true,
"requires": {
"tslib": "^2.1.0"
}
},
"tslib": { "tslib": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
@ -2901,6 +2893,19 @@
"lodash": "^4.17.4" "lodash": "^4.17.4"
} }
}, },
"babel-helper-remap-async-to-generator": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
"integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
"dev": true,
"requires": {
"babel-helper-function-name": "^6.24.1",
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1",
"babel-traverse": "^6.24.1",
"babel-types": "^6.24.1"
}
},
"babel-helper-replace-supers": { "babel-helper-replace-supers": {
"version": "6.24.1", "version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
@ -3039,6 +3044,12 @@
} }
} }
}, },
"babel-plugin-syntax-async-functions": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
"integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
"dev": true
},
"babel-plugin-syntax-dynamic-import": { "babel-plugin-syntax-dynamic-import": {
"version": "6.18.0", "version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
@ -3063,6 +3074,17 @@
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true "dev": true
}, },
"babel-plugin-transform-async-to-generator": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
"integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
"dev": true,
"requires": {
"babel-helper-remap-async-to-generator": "^6.24.1",
"babel-plugin-syntax-async-functions": "^6.8.0",
"babel-runtime": "^6.22.0"
}
},
"babel-plugin-transform-es2015-arrow-functions": { "babel-plugin-transform-es2015-arrow-functions": {
"version": "6.22.0", "version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
@ -3558,6 +3580,12 @@
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==",
"dev": true "dev": true
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
} }
} }
}, },
@ -4481,9 +4509,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001275", "version": "1.0.30001282",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001275.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001282.tgz",
"integrity": "sha512-ihJVvj8RX0kn9GgP43HKhb5q9s2XQn4nEQhdldEJvZhCsuiB2XOq6fAMYQZaN6FPWfsr2qU0cdL0CSbETwbJAg==", "integrity": "sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg==",
"dev": true "dev": true
}, },
"canvas-fit": { "canvas-fit": {
@ -4627,9 +4655,9 @@
} }
}, },
"chromedriver": { "chromedriver": {
"version": "94.0.0", "version": "95.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-94.0.0.tgz", "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-95.0.0.tgz",
"integrity": "sha512-x4hK7R7iOyAhdLHJEcOyGBW/oa2kno6AqpHVLd+n3G7c2Vk9XcAXMz84XhNItqykJvTc6E3z/JRIT1eHYH//Eg==", "integrity": "sha512-HwSg7S0ZZYsHTjULwxFHrrUqEpz1+ljDudJM3eOquvqD5QKnR5pSe/GlBTY9UU2tVFRYz8bEHYC4Y8qxciQiLQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@testim/chrome-version": "^1.0.7", "@testim/chrome-version": "^1.0.7",
@ -6263,9 +6291,9 @@
"dev": true "dev": true
}, },
"ignore": { "ignore": {
"version": "5.1.8", "version": "5.1.9",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz",
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==",
"dev": true "dev": true
}, },
"is-extglob": { "is-extglob": {
@ -8492,9 +8520,9 @@
} }
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.4", "version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==", "integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
"dev": true "dev": true
}, },
"font-atlas": { "font-atlas": {
@ -19164,9 +19192,9 @@
} }
}, },
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.11.1", "version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true "dev": true
}, },
"regenerator-transform": { "regenerator-transform": {
@ -20524,21 +20552,35 @@
} }
}, },
"scratch-blocks": { "scratch-blocks": {
"version": "0.1.0-prerelease.20211103084955", "version": "0.1.0-prerelease.20211110095305",
"resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20211103084955.tgz", "resolved": "https://registry.npmjs.org/scratch-blocks/-/scratch-blocks-0.1.0-prerelease.20211110095305.tgz",
"integrity": "sha512-CELZCOHCLAZktFBNuzE4gn/c+uXTlM/AakQOQAZG3VQNpRolzsKdCFdKjmFGGLTrSV9aUO1GsBRtwcWsgdJXIA==", "integrity": "sha512-EJC1kRxMl/e80QWOI4GqJBuYwJ2jX0v/QhiHRY97m5uys5mozBWgoxT/f4qPRK1KYUP36ACWMpjkhftvqxRYwA==",
"dev": true, "dev": true,
"requires": { "requires": {
"exports-loader": "0.6.3", "exports-loader": "0.6.3",
"google-closure-library": "20190301.0.0", "google-closure-library": "20190301.0.0",
"imports-loader": "0.6.5", "imports-loader": "0.6.5",
"scratch-l10n": "3.14.20211103031555" "scratch-l10n": "3.14.20211110031601"
},
"dependencies": {
"scratch-l10n": {
"version": "3.14.20211110031601",
"resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.14.20211110031601.tgz",
"integrity": "sha512-XJQv2MSiu3bMkFPBSp7U0+T/omMiHnL60KGEA3OLdfX0hUgwwWoOduvx3O7rIpLp53zmOLds3eAa3hd/wh1E+g==",
"dev": true,
"requires": {
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"babel-plugin-react-intl": "^3.0.1",
"transifex": "1.6.6"
}
}
} }
}, },
"scratch-gui": { "scratch-gui": {
"version": "0.1.0-prerelease.20211103150403", "version": "0.1.0-prerelease.20211117061326",
"resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20211103150403.tgz", "resolved": "https://registry.npmjs.org/scratch-gui/-/scratch-gui-0.1.0-prerelease.20211117061326.tgz",
"integrity": "sha512-SA7pb/Bhz6CwJvAbWegtnrxfuc+rvEO3WBYQkV7Q/SxmXKO4GYdqSc4mMHo6oDm08RMcDdLrD/CEIL/KZi67PA==", "integrity": "sha512-+JF0VztQWTtbVFnsRWpINXCU0HpbmV79or80Ho3akOvYkrJtGdMZt1lyEqYUflBAGRrLthZsefl/wiTLay6wfw==",
"dev": true, "dev": true,
"requires": { "requires": {
"arraybuffer-loader": "^1.0.6", "arraybuffer-loader": "^1.0.6",
@ -20589,14 +20631,14 @@
"redux": "3.7.2", "redux": "3.7.2",
"redux-throttle": "0.1.1", "redux-throttle": "0.1.1",
"scratch-audio": "0.1.0-prerelease.20200528195344", "scratch-audio": "0.1.0-prerelease.20200528195344",
"scratch-blocks": "0.1.0-prerelease.20211103084955", "scratch-blocks": "0.1.0-prerelease.20211110095305",
"scratch-l10n": "3.14.20211103031555", "scratch-l10n": "3.14.20211117031600",
"scratch-paint": "0.2.0-prerelease.20211027080909", "scratch-paint": "0.2.0-prerelease.20211027080909",
"scratch-render": "0.1.0-prerelease.20211028200436", "scratch-render": "0.1.0-prerelease.20211028200436",
"scratch-render-fonts": "1.0.0-prerelease.20210401210003", "scratch-render-fonts": "1.0.0-prerelease.20210401210003",
"scratch-storage": "1.3.5", "scratch-storage": "1.3.5",
"scratch-svg-renderer": "0.2.0-prerelease.20210727023023", "scratch-svg-renderer": "0.2.0-prerelease.20210727023023",
"scratch-vm": "0.2.0-prerelease.20211103090905", "scratch-vm": "0.2.0-prerelease.20211110140254",
"startaudiocontext": "1.2.1", "startaudiocontext": "1.2.1",
"style-loader": "^0.23.0", "style-loader": "^0.23.0",
"text-encoding": "0.7.0", "text-encoding": "0.7.0",
@ -20636,13 +20678,13 @@
"dev": true "dev": true
}, },
"browserslist": { "browserslist": {
"version": "4.17.6", "version": "4.18.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.18.1.tgz",
"integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", "integrity": "sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"caniuse-lite": "^1.0.30001274", "caniuse-lite": "^1.0.30001280",
"electron-to-chromium": "^1.3.886", "electron-to-chromium": "^1.3.896",
"escalade": "^3.1.1", "escalade": "^3.1.1",
"node-releases": "^2.0.1", "node-releases": "^2.0.1",
"picocolors": "^1.0.0" "picocolors": "^1.0.0"
@ -20747,9 +20789,9 @@
"dev": true "dev": true
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.887", "version": "1.3.900",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.887.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.900.tgz",
"integrity": "sha512-QQUumrEjFDKSVYVdaeBmFdyQGoaV+fCSMyWHvfx/u22bRHSTeBQYt6P4jMY+gFd4kgKB9nqk7RMtWkDB49OYPA==", "integrity": "sha512-SuXbQD8D4EjsaBaJJxySHbC+zq8JrFfxtb4GIr4E9n1BcROyMcRrJCYQNpJ9N+Wjf5mFp7Wp0OHykd14JNEzzQ==",
"dev": true "dev": true
}, },
"has-flag": { "has-flag": {
@ -21012,9 +21054,9 @@
} }
}, },
"scratch-l10n": { "scratch-l10n": {
"version": "3.14.20211103031555", "version": "3.14.20211117031600",
"resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.14.20211103031555.tgz", "resolved": "https://registry.npmjs.org/scratch-l10n/-/scratch-l10n-3.14.20211117031600.tgz",
"integrity": "sha512-eJrTp6JJyTWeyXiWuLUPtGfy7tG4sGHeCz6gNYtH2TMLwzQfu2r2RRbt29HS7zkkxdnqWZjVkOxVnosWb/1EuQ==", "integrity": "sha512-ekVIL9BLg6ZISYYbd3ID35rg0NcCyYvrrmgtIwUl0y7bgc+DSFBaZZoQN0rBahIM6tsEDpbc278nMDHKMhs0VA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/cli": "^7.1.2", "@babel/cli": "^7.1.2",
@ -21243,9 +21285,9 @@
"dev": true "dev": true
}, },
"scratch-vm": { "scratch-vm": {
"version": "0.2.0-prerelease.20211103090905", "version": "0.2.0-prerelease.20211110140254",
"resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-0.2.0-prerelease.20211103090905.tgz", "resolved": "https://registry.npmjs.org/scratch-vm/-/scratch-vm-0.2.0-prerelease.20211110140254.tgz",
"integrity": "sha512-nfqvuNCOLzippBHcbfVQoWXVOLTdrlIXfFnhYTzVthLsl32ApUsNU9P3iA50HsAkwqvZmcHM4SQFLXZEJgonkQ==", "integrity": "sha512-6gNNDXJg3WagT/tA7bjLJcQeDqhvu/FZVdIAlS3A96C/6sT3jiWljDeRpzl/EbJWAxwzbQ6CBiZ3ZDf9eLgQ2Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"@vernier/godirect": "1.5.0", "@vernier/godirect": "1.5.0",

View file

@ -7,14 +7,8 @@
"test": "npm run test:lint && npm run build && npm run test:unit", "test": "npm run test:lint && npm run build && npm run test:unit",
"test:lint": "eslint . --ext .js,.jsx,.json", "test:lint": "eslint . --ext .js,.jsx,.json",
"test:lint:ci": "eslint . --ext .js,.jsx,.json --format junit -o ./test/results/lint-results.xml", "test:lint:ci": "eslint . --ext .js,.jsx,.json --format junit -o ./test/results/lint-results.xml",
"test:integration": "npm run test:integration:jest && npm run test:smoke", "test:integration": "jest ./test/integration/*.test.js --reporters=default --runInBand",
"test:integration:jest": "jest ./test/integration/*.test.js --reporters=default --runInBand", "test:integration:remote": "SMOKE_REMOTE=true jest ./test/integration/*.test.js --reporters=default --runInBand",
"test:integration:remote": "npm run test:integration:jest:remote && npm run test:smoke:sauce",
"test:integration:jest:remote": "SMOKE_REMOTE=true jest ./test/integration/*.test.js --reporters=default --runInBand",
"test:smoke": "tap ./test/integration-legacy/smoke-testing/*.js --timeout=3600 --no-coverage -R classic",
"test:smoke:verbose": "tap ./test/integration-legacy/smoke-testing/*.js --timeout=3600 --no-coverage -R spec",
"test:smoke:sauce": "SMOKE_REMOTE=true tap ./test/integration-legacy/smoke-testing/*.js --timeout=60000 --no-coverage -R classic",
"test:smoke:convertReportToXunit": "tap ./test/results/integration-raw-tap.tap --no-coverage -R xunit > ./test/results/integration-tap-results.xml",
"test:unit": "npm run test:unit:jest && npm run test:unit:tap", "test:unit": "npm run test:unit:jest && npm run test:unit:tap",
"test:unit:jest": "npm run test:unit:jest:unit && npm run test:unit:jest:localization", "test:unit:jest": "npm run test:unit:jest:unit && npm run test:unit:jest:localization",
"test:unit:jest:unit": "jest ./test/unit/ --reporters=default", "test:unit:jest:unit": "jest ./test/unit/ --reporters=default",
@ -63,7 +57,7 @@
}, },
"devDependencies": { "devDependencies": {
"@formatjs/intl-locale": "2.4.34", "@formatjs/intl-locale": "2.4.34",
"@formatjs/intl-pluralrules": "4.0.28", "@formatjs/intl-pluralrules": "4.1.0",
"@formatjs/intl-relativetimeformat": "8.1.8", "@formatjs/intl-relativetimeformat": "8.1.8",
"async": "3.1.0", "async": "3.1.0",
"autoprefixer": "6.3.6", "autoprefixer": "6.3.6",
@ -72,12 +66,13 @@
"babel-eslint": "10.0.3", "babel-eslint": "10.0.3",
"babel-loader": "7.1.0", "babel-loader": "7.1.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-async-to-generator": "6.24.1",
"babel-plugin-transform-object-rest-spread": "6.26.0", "babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-plugin-transform-require-context": "0.1.1", "babel-plugin-transform-require-context": "0.1.1",
"babel-preset-es2015": "6.22.0", "babel-preset-es2015": "6.22.0",
"babel-preset-react": "6.22.0", "babel-preset-react": "6.22.0",
"bowser": "1.9.4", "bowser": "1.9.4",
"chromedriver": "94.0.0", "chromedriver": "95.0.0",
"classnames": "2.2.5", "classnames": "2.2.5",
"cookie": "0.4.1", "cookie": "0.4.1",
"copy-webpack-plugin": "4.6.0", "copy-webpack-plugin": "4.6.0",
@ -130,9 +125,10 @@
"redux": "3.5.2", "redux": "3.5.2",
"redux-mock-store": "1.5.4", "redux-mock-store": "1.5.4",
"redux-thunk": "2.0.1", "redux-thunk": "2.0.1",
"regenerator-runtime": "0.13.9",
"sass-loader": "6.0.6", "sass-loader": "6.0.6",
"scratch-gui": "0.1.0-prerelease.20211103150403", "scratch-gui": "0.1.0-prerelease.20211117061326",
"scratch-l10n": "3.14.20211103031555", "scratch-l10n": "3.14.20211117031600",
"selenium-webdriver": "3.6.0", "selenium-webdriver": "3.6.0",
"slick-carousel": "1.6.0", "slick-carousel": "1.6.0",
"style-loader": "0.12.3", "style-loader": "0.12.3",

View file

@ -1,11 +1,13 @@
import 'regenerator-runtime/runtime'; // Needed for async/await
const jar = require('./lib/jar'); const jar = require('./lib/jar');
import intlPolyfill from './lib/intl-polyfill';
/** /**
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
* L10N * L10N
* ----------------------------------------------------------------------------- * -----------------------------------------------------------------------------
*/ */
(() => { (async () => {
/* /*
* Bind locale code from cookie if available. Uses navigator language API as a fallback. * Bind locale code from cookie if available. Uses navigator language API as a fallback.
* *
@ -35,6 +37,7 @@ const jar = require('./lib/jar');
window._locale = updateLocale(); window._locale = updateLocale();
document.documentElement.lang = window._locale; document.documentElement.lang = window._locale;
await intlPolyfill(window._locale);
})(); })();
/** /**

View file

@ -1,8 +1,6 @@
// IMPORTANT: any changes to the time algorithm also need to be made in the corresponding // IMPORTANT: any changes to the time algorithm also need to be made in the corresponding
// scratchr2 file 'lib/format-time.js' // scratchr2 file 'lib/format-time.js'
require('./relative-time-polyfill');
/** /**
Given a timestamp in the future, calculate the largest, closest unit to show. Given a timestamp in the future, calculate the largest, closest unit to show.
On the high end we stop at hours. e.g. 15 days is still counted in hours not days or weeks. On the high end we stop at hours. e.g. 15 days is still counted in hours not days or weeks.

313
src/lib/intl-polyfill.js Normal file
View file

@ -0,0 +1,313 @@
// this file should only be `required` in the format-time
// when Intl.RelativeTimeFormat is not available (Safari < 14), but
// we're not currently able to do the code splitting in www, and it
// is always included. To reduce the amount of data that's loaded limit
// the number of languages loaded to just the top few that are still using
// safari <14. These seven account for most uses.
// relativetimeformat depends on locale which also needs to be polyfilled in
// safari <14
// The plural rules is required for safari 12.
import 'regenerator-runtime/runtime'; // Needed for async/await
import {shouldPolyfill as shouldPolyfillLocale} from '@formatjs/intl-locale/should-polyfill';
import {shouldPolyfill as shouldPolyfillRelativeTimeFormat} from '@formatjs/intl-relativetimeformat/should-polyfill';
import {shouldPolyfill as shouldPolyfillPluralRules} from '@formatjs/intl-pluralrules/should-polyfill';
/**
* polyfill all the parts needed from intl
* @param {string} locale currently selected locale
* @return {Promise} returns a promise that resolves when everything is loaded
*/
const intlPolyfill = async function (locale) {
if (!(shouldPolyfillLocale() ||
shouldPolyfillPluralRules(locale) ||
shouldPolyfillRelativeTimeFormat(locale))) {
return;
}
if (shouldPolyfillRelativeTimeFormat(locale)) {
await import('@formatjs/intl-relativetimeformat/polyfill');
}
if (shouldPolyfillPluralRules(locale)) {
await import('@formatjs/intl-pluralrules/polyfill');
}
if (shouldPolyfillLocale(locale)) {
await import('@formatjs/intl-locale/polyfill');
}
switch (locale.toLowerCase().split('-')[0]) {
case 'af':
await import('@formatjs/intl-relativetimeformat/locale-data/af');
await import('@formatjs/intl-pluralrules/locale-data/af');
break;
case 'ar':
await import('@formatjs/intl-relativetimeformat/locale-data/ar');
await import('@formatjs/intl-pluralrules/locale-data/ar');
break;
case 'am':
await import('@formatjs/intl-relativetimeformat/locale-data/am');
await import('@formatjs/intl-pluralrules/locale-data/am');
break;
case 'an':
await import('@formatjs/intl-relativetimeformat/locale-data/en');
await import('@formatjs/intl-pluralrules/locale-data/an');
break;
case 'az':
await import('@formatjs/intl-relativetimeformat/locale-data/az');
await import('@formatjs/intl-pluralrules/locale-data/az');
break;
case 'id':
await import('@formatjs/intl-relativetimeformat/locale-data/id');
await import('@formatjs/intl-pluralrules/locale-data/id');
break;
case 'bn':
await import('@formatjs/intl-relativetimeformat/locale-data/bn');
await import('@formatjs/intl-pluralrules/locale-data/bn');
break;
case 'be':
await import('@formatjs/intl-relativetimeformat/locale-data/be');
await import('@formatjs/intl-pluralrules/locale-data/be');
break;
case 'bg':
await import('@formatjs/intl-relativetimeformat/locale-data/bg');
await import('@formatjs/intl-pluralrules/locale-data/bg');
break;
case 'ca':
await import('@formatjs/intl-relativetimeformat/locale-data/ca');
await import('@formatjs/intl-pluralrules/locale-data/ca');
break;
case 'cs':
await import('@formatjs/intl-relativetimeformat/locale-data/cs');
await import('@formatjs/intl-pluralrules/locale-data/cs');
break;
case 'cy':
await import('@formatjs/intl-relativetimeformat/locale-data/cy');
await import('@formatjs/intl-pluralrules/locale-data/cy');
break;
case 'da':
await import('@formatjs/intl-relativetimeformat/locale-data/da');
await import('@formatjs/intl-pluralrules/locale-data/da');
break;
case 'de':
await import('@formatjs/intl-relativetimeformat/locale-data/de');
await import('@formatjs/intl-pluralrules/locale-data/de');
break;
case 'et':
await import('@formatjs/intl-relativetimeformat/locale-data/et');
await import('@formatjs/intl-pluralrules/locale-data/et');
break;
case 'el':
await import('@formatjs/intl-relativetimeformat/locale-data/el');
await import('@formatjs/intl-pluralrules/locale-data/el');
break;
case 'en':
await import('@formatjs/intl-relativetimeformat/locale-data/en');
await import('@formatjs/intl-pluralrules/locale-data/en');
break;
case 'es':
case 'rap':
case 'qu':
await import('@formatjs/intl-relativetimeformat/locale-data/es');
await import('@formatjs/intl-pluralrules/locale-data/es');
break;
case 'eu':
await import('@formatjs/intl-relativetimeformat/locale-data/eu');
await import('@formatjs/intl-pluralrules/locale-data/eu');
break;
case 'fa':
await import('@formatjs/intl-relativetimeformat/locale-data/fa');
await import('@formatjs/intl-pluralrules/locale-data/fa');
break;
case 'fr':
case 'ht':
await import('@formatjs/intl-relativetimeformat/locale-data/fr');
await import('@formatjs/intl-pluralrules/locale-data/fr');
break;
case 'fy':
await import('@formatjs/intl-relativetimeformat/locale-data/fy');
await import('@formatjs/intl-pluralrules/locale-data/fy');
break;
case 'ga':
await import('@formatjs/intl-relativetimeformat/locale-data/ga');
await import('@formatjs/intl-pluralrules/locale-data/ga');
break;
case 'gd':
await import('@formatjs/intl-relativetimeformat/locale-data/gd');
await import('@formatjs/intl-pluralrules/locale-data/gd');
break;
case 'gl':
await import('@formatjs/intl-relativetimeformat/locale-data/gl');
await import('@formatjs/intl-pluralrules/locale-data/gl');
break;
case 'ko':
await import('@formatjs/intl-relativetimeformat/locale-data/ko');
await import('@formatjs/intl-pluralrules/locale-data/ko');
break;
case 'hy':
await import('@formatjs/intl-relativetimeformat/locale-data/hy');
await import('@formatjs/intl-pluralrules/locale-data/hy');
break;
case 'he':
await import('@formatjs/intl-relativetimeformat/locale-data/he');
await import('@formatjs/intl-pluralrules/locale-data/he');
break;
case 'hr':
await import('@formatjs/intl-relativetimeformat/locale-data/hr');
await import('@formatjs/intl-pluralrules/locale-data/hr');
break;
case 'xh':
await import('@formatjs/intl-relativetimeformat/locale-data/xh');
await import('@formatjs/intl-pluralrules/locale-data/xh');
break;
case 'zu':
await import('@formatjs/intl-relativetimeformat/locale-data/zu');
await import('@formatjs/intl-pluralrules/locale-data/zu');
break;
case 'is':
await import('@formatjs/intl-relativetimeformat/locale-data/is');
await import('@formatjs/intl-pluralrules/locale-data/is');
break;
case 'it':
await import('@formatjs/intl-relativetimeformat/locale-data/it');
await import('@formatjs/intl-pluralrules/locale-data/it');
break;
case 'ka':
await import('@formatjs/intl-relativetimeformat/locale-data/ka');
await import('@formatjs/intl-pluralrules/locale-data/ka');
break;
case 'kk':
await import('@formatjs/intl-relativetimeformat/locale-data/kk');
await import('@formatjs/intl-pluralrules/locale-data/kk');
break;
case 'sw':
await import('@formatjs/intl-relativetimeformat/locale-data/sw');
await import('@formatjs/intl-pluralrules/locale-data/sw');
break;
case 'ku':
await import('@formatjs/intl-relativetimeformat/locale-data/ku');
await import('@formatjs/intl-pluralrules/locale-data/ku');
break;
case 'ckb':
await import('@formatjs/intl-relativetimeformat/locale-data/ckb');
await import('@formatjs/intl-pluralrules/locale-data/ckb');
break;
case 'lv':
await import('@formatjs/intl-relativetimeformat/locale-data/lv');
await import('@formatjs/intl-pluralrules/locale-data/lv');
break;
case 'lt':
await import('@formatjs/intl-relativetimeformat/locale-data/lt');
await import('@formatjs/intl-pluralrules/locale-data/lt');
break;
case 'hu':
await import('@formatjs/intl-relativetimeformat/locale-data/hu');
await import('@formatjs/intl-pluralrules/locale-data/hu');
break;
case 'mi':
await import('@formatjs/intl-relativetimeformat/locale-data/mi');
await import('@formatjs/intl-pluralrules/locale-data/en');
break;
case 'mn':
await import('@formatjs/intl-relativetimeformat/locale-data/mn');
await import('@formatjs/intl-pluralrules/locale-data/mn');
break;
case 'nl':
await import('@formatjs/intl-relativetimeformat/locale-data/nl');
await import('@formatjs/intl-pluralrules/locale-data/nl');
break;
case 'ja':
await import('@formatjs/intl-relativetimeformat/locale-data/ja');
await import('@formatjs/intl-pluralrules/locale-data/ja');
break;
case 'nb':
await import('@formatjs/intl-relativetimeformat/locale-data/nb');
await import('@formatjs/intl-pluralrules/locale-data/nb');
break;
case 'nn':
await import('@formatjs/intl-relativetimeformat/locale-data/nn');
await import('@formatjs/intl-pluralrules/locale-data/nn');
break;
case 'or':
await import('@formatjs/intl-relativetimeformat/locale-data/or');
await import('@formatjs/intl-pluralrules/locale-data/or');
break;
case 'uz':
await import('@formatjs/intl-relativetimeformat/locale-data/uz');
await import('@formatjs/intl-pluralrules/locale-data/uz');
break;
case 'th':
await import('@formatjs/intl-relativetimeformat/locale-data/th');
await import('@formatjs/intl-pluralrules/locale-data/th');
break;
case 'km':
await import('@formatjs/intl-relativetimeformat/locale-data/km');
await import('@formatjs/intl-pluralrules/locale-data/km');
break;
case 'pl':
await import('@formatjs/intl-relativetimeformat/locale-data/pl');
await import('@formatjs/intl-pluralrules/locale-data/pl');
break;
case 'pt':
await import('@formatjs/intl-relativetimeformat/locale-data/pt');
await import('@formatjs/intl-pluralrules/locale-data/pt');
break;
case 'ro':
await import('@formatjs/intl-relativetimeformat/locale-data/ro');
await import('@formatjs/intl-pluralrules/locale-data/ro');
break;
case 'ru':
await import('@formatjs/intl-relativetimeformat/locale-data/ru');
await import('@formatjs/intl-pluralrules/locale-data/ru');
break;
case 'nso':
await import('@formatjs/intl-relativetimeformat/locale-data/en');
await import('@formatjs/intl-pluralrules/locale-data/nso');
break;
case 'tn':
await import('@formatjs/intl-relativetimeformat/locale-data/en');
await import('@formatjs/intl-pluralrules/locale-data/tn');
break;
case 'sk':
await import('@formatjs/intl-relativetimeformat/locale-data/sk');
await import('@formatjs/intl-pluralrules/locale-data/sk');
break;
case 'sl':
await import('@formatjs/intl-relativetimeformat/locale-data/sl');
await import('@formatjs/intl-pluralrules/locale-data/sl');
break;
case 'sr':
await import('@formatjs/intl-relativetimeformat/locale-data/sr');
await import('@formatjs/intl-pluralrules/locale-data/sr');
break;
case 'fi':
await import('@formatjs/intl-relativetimeformat/locale-data/fi');
await import('@formatjs/intl-pluralrules/locale-data/fi');
break;
case 'sv':
await import('@formatjs/intl-relativetimeformat/locale-data/sv');
await import('@formatjs/intl-pluralrules/locale-data/sv');
break;
case 'vi':
await import('@formatjs/intl-relativetimeformat/locale-data/vi');
await import('@formatjs/intl-pluralrules/locale-data/vi');
break;
case 'tr':
await import('@formatjs/intl-relativetimeformat/locale-data/tr');
await import('@formatjs/intl-pluralrules/locale-data/tr');
break;
case 'uk':
await import('@formatjs/intl-relativetimeformat/locale-data/uk');
await import('@formatjs/intl-pluralrules/locale-data/uk');
break;
case 'zh':
await import('@formatjs/intl-relativetimeformat/locale-data/zh');
await import('@formatjs/intl-pluralrules/locale-data/zh');
break;
default:
await import('@formatjs/intl-relativetimeformat/locale-data/en');
await import('@formatjs/intl-pluralrules/locale-data/en');
break;
}
};
export default intlPolyfill;

View file

@ -1,20 +0,0 @@
// this file should only be `required` in the format-time
// when Intl.RelativeTimeFormat is not available (Safari < 14), but
// we're not currently able to do the code splitting in www, and it
// is always included. To reduce the amount of data that's loaded limit
// the number of languages loaded to just the top few that are still using
// safari <14. These seven account for most uses.
// relativetimeformat depends on locale which also needs to be polyfilled in
// safari <14
// The plural rules is required for safari 12.
require('@formatjs/intl-locale/polyfill');
require('@formatjs/intl-pluralrules/polyfill');
require('@formatjs/intl-pluralrules/locale-data/en');
require('@formatjs/intl-relativetimeformat/polyfill');
require('@formatjs/intl-relativetimeformat/locale-data/en');
require('@formatjs/intl-relativetimeformat/locale-data/ar');
require('@formatjs/intl-relativetimeformat/locale-data/es');
require('@formatjs/intl-relativetimeformat/locale-data/fr');
require('@formatjs/intl-relativetimeformat/locale-data/ja');
require('@formatjs/intl-relativetimeformat/locale-data/tr');
require('@formatjs/intl-relativetimeformat/locale-data/zh');

View file

@ -14,7 +14,14 @@ const About = () => (
<div className="masthead"> <div className="masthead">
<div> <div>
<p><FormattedMessage id="about.introOne" /></p> <p><FormattedMessage
id="about.introOne"
values={{foundationLink: (
<a href="https://www.scratchfoundation.org/">
<FormattedMessage id="about.foundationText" />
</a>
)}}
/></p>
<p><FormattedMessage id="about.introTwo" /></p> <p><FormattedMessage id="about.introTwo" /></p>
<p><FormattedMessage id="about.introThree" /></p> <p><FormattedMessage id="about.introThree" /></p>
@ -64,7 +71,8 @@ const About = () => (
<p><FormattedMessage <p><FormattedMessage
id="about.aroundTheWorldDescription" id="about.aroundTheWorldDescription"
values={{ values={{
languageCount: 60, countryCount: 200,
languageCount: 70,
translationLink: ( translationLink: (
<a <a
href="https://github.com/LLK/scratch-l10n/wiki/Guide-for-Scratch-Translators" href="https://github.com/LLK/scratch-l10n/wiki/Guide-for-Scratch-Translators"
@ -126,11 +134,6 @@ const About = () => (
<FormattedMessage id="about.researchLinkText" /> <FormattedMessage id="about.researchLinkText" />
</a> </a>
), ),
spfaLink: (
<a href="http://web.media.mit.edu/~mres/papers/Scratch-CACM-final.pdf">
<FormattedMessage id="about.spfaLinkText" />
</a>
),
lifelongKindergartenGroupLink: ( lifelongKindergartenGroupLink: (
<a href="https://www.media.mit.edu/groups/lifelong-kindergarten/overview/"> <a href="https://www.media.mit.edu/groups/lifelong-kindergarten/overview/">
<FormattedMessage id="about.lifelongKindergartenGroupLinkText" /> <FormattedMessage id="about.lifelongKindergartenGroupLinkText" />
@ -171,9 +174,6 @@ const About = () => (
<li> <li>
<h3><FormattedMessage id="about.learnMore" /></h3> <h3><FormattedMessage id="about.learnMore" /></h3>
<ul className="list"> <ul className="list">
<li>
<a href="/ideas"><FormattedMessage id="about.learnMoreHelp" /></a>
</li>
<li> <li>
<a href="/faq"><FormattedMessage id="about.learnMoreFaq" /></a> <a href="/faq"><FormattedMessage id="about.learnMoreFaq" /></a>
</li> </li>
@ -181,7 +181,7 @@ const About = () => (
<a href="/parents"><FormattedMessage id="about.learnMoreParents" /></a> <a href="/parents"><FormattedMessage id="about.learnMoreParents" /></a>
</li> </li>
<li> <li>
<a href="/credits"><FormattedMessage id="about.learnMoreCredits" /></a> <a href="/educators"><FormattedMessage id="about.learnMoreEducators" /></a>
</li> </li>
<li> <li>
<a href="/annual-report"><FormattedMessage id="about.learnMoreAnnualReport" /></a> <a href="/annual-report"><FormattedMessage id="about.learnMoreAnnualReport" /></a>
@ -203,11 +203,6 @@ const About = () => (
<FormattedMessage id="about.donorsLinkText" /> <FormattedMessage id="about.donorsLinkText" />
</a> </a>
), ),
annualReportLink: (
<a href="/annual-report">
<FormattedMessage id="about.annualReportLinkText" />
</a>
),
donateLink: ( donateLink: (
<a <a
href="//secure.donationpay.org/scratchfoundation/" href="//secure.donationpay.org/scratchfoundation/"
@ -216,11 +211,6 @@ const About = () => (
> >
<FormattedMessage id="about.donateLinkText" /> <FormattedMessage id="about.donateLinkText" />
</a> </a>
),
donateemail: (
<a href="mailto:donate@scratch.mit.edu">
donate@scratch.mit.edu
</a>
) )
}} }}
/></p> /></p>

View file

@ -1,23 +1,23 @@
{ {
"about.introOne": "With Scratch, you can program your own interactive stories, games, and animations — and share your creations with others in the online community.", "about.introOne": "Scratch is the worlds largest coding community for children and a coding language with a simple visual interface that allows young people to create digital stories, games, and animations. Scratch is designed, developed, and moderated by the {foundationLink}, a nonprofit organization. ",
"about.introTwo": "Scratch helps young people learn to think creatively, reason systematically, and work collaboratively — essential skills for life in the 21st century.", "about.introTwo": "Scratch promotes computational thinking and problem solving skills; creative teaching and learning; self-expression and collaboration; and equity in computing.",
"about.introThree": "Scratch is designed, developed, and moderated by the Scratch Foundation, a nonprofit organization. It is provided free of charge.", "about.introThree": "Scratch is always free and is available in more than 70 languages.",
"about.foundationText": "Scratch Foundation",
"about.introParents": "Info for parents", "about.introParents": "Info for parents",
"about.introEducators": "Info for educators", "about.introEducators": "Info for educators",
"about.whoUsesScratch": "Who Uses Scratch?", "about.whoUsesScratch": "Who Uses Scratch?",
"about.whoUsesScratchDescription": "Scratch is designed especially for ages 8 to 16, but is used by people of all ages. Millions of people are creating Scratch projects in a wide variety of settings, including homes, schools, museums, libraries, and community centers.", "about.whoUsesScratchDescription": "Scratch is designed especially for ages 8 to 16, but is used by people of all ages. Millions of people are creating Scratch projects in a wide variety of settings, including homes, schools, museums, libraries, and community centers.",
"about.aroundTheWorld": "Around the World", "about.aroundTheWorld": "Around the World",
"about.aroundTheWorldDescription": "Scratch is used in more than 150 different countries and available in more than {languageCount} languages. To change languages, click the menu at the bottom of the page. Or, in the Project Editor, click the globe at the top of the page. To add or improve a translation, see the {translationLink} page.", "about.aroundTheWorldDescription": "Scratch is used in more than {countryCount} different countries and territories and is available in more than {languageCount} languages. To change languages, click the menu at the bottom of the page. Or, in the Project Editor, click the globe at the top of the page. To add or improve a translation, see the {translationLink} page.",
"about.translationLinkText": "translation", "about.translationLinkText": "translation",
"about.quotes": "Quotes", "about.quotes": "Quotes",
"about.quotesDescription": "The Scratch Team has received many emails from youth, parents, and educators expressing thanks for Scratch. Want to see what people are saying? You can read a collection of the {quotesLink} we've received.", "about.quotesDescription": "The Scratch Team has received many emails from youth, parents, and educators expressing thanks for Scratch. Want to see what people are saying? You can read a collection of the {quotesLink} we've received.",
"about.quotesLinkText": "quotes", "about.quotesLinkText": "quotes",
"about.learnMore": "Learn More About Scratch", "about.learnMore": "Learn More About Scratch",
"about.learnMoreHelp": "Ideas Page",
"about.learnMoreFaq": "Frequently Asked Questions", "about.learnMoreFaq": "Frequently Asked Questions",
"about.learnMoreParents": "Information for Parents", "about.learnMoreParents": "Information for Parents",
"about.learnMoreCredits": "Our Team", "about.learnMoreEducators": "Information for Educators",
"about.learnMoreAnnualReport": "Annual Report 2019", "about.learnMoreAnnualReport": "Annual Report",
"about.literacy": "Learn to Code, Code to Learn", "about.literacy": "Learn to Code, Code to Learn",
"about.literacyDescription": "The ability to code computer programs is an important part of literacy in todays society. When people learn to code in Scratch, they learn important strategies for solving problems, designing projects, and communicating ideas.", "about.literacyDescription": "The ability to code computer programs is an important part of literacy in todays society. When people learn to code in Scratch, they learn important strategies for solving problems, designing projects, and communicating ideas.",
"about.schools": "Scratch in Schools", "about.schools": "Scratch in Schools",
@ -25,17 +25,16 @@
"about.scratchForEducatorsLinkText": "Scratch For Educators", "about.scratchForEducatorsLinkText": "Scratch For Educators",
"about.scratchedLinkText": "ScratchEd website", "about.scratchedLinkText": "ScratchEd website",
"about.research": "Research", "about.research": "Research",
"about.researchDescription": "The {lifelongKindergartenGroupLink} and collaborators are researching how young people create, collaborate, and learn with Scratch. For an overview, see the article {codingAtACrossroadsLink} and the book {lifelongKindergartenBookLink}. To find out more about the use of Scratch, see the {statisticsLink} page and the Scratch {annualReportLink}.", "about.researchDescription": "The {lifelongKindergartenGroupLink} and collaborators are {researchLink} how young people create, collaborate, and learn with Scratch. For an overview, see the article {codingAtACrossroadsLink} and the book {lifelongKindergartenBookLink}. To find out more about the use of Scratch, see the {statisticsLink} page and the Scratch {annualReportLink}.",
"about.spfaLinkText": "Scratch: Programming for All", "about.researchLinkText": "researching",
"about.researchLinkText": "research",
"about.statisticsLinkText": "statistics", "about.statisticsLinkText": "statistics",
"about.lifelongKindergartenGroupLinkText": "Lifelong Kindergarten group", "about.lifelongKindergartenGroupLinkText": "Lifelong Kindergarten group",
"about.codingAtACrossroadsLinkText": "Coding at a Crossroads", "about.codingAtACrossroadsLinkText": "Coding at a Crossroads",
"about.lifelongKindergartenBookLinkText": "Lifelong Kindergarten", "about.lifelongKindergartenBookLinkText": "Lifelong Kindergarten",
"about.annualReportLinkText": "Annual Report", "about.annualReportLinkText": "Annual Report",
"about.support": "Support and Funding", "about.support": "Support and Funding",
"about.supportDescription": "Scratch is available for free, thanks to support from our {donorsLink}. For more information, see our {annualReportLink}. You can support Scratch by making a donation.", "about.supportDescription": "Scratch is available for free, thanks to support from our {donorsLink}. This support helps us provide kids around the world with opportunities to imagine, create, and share. You can support Scratch by making a donation {donateLink}.",
"about.donorsLinkText": "donors", "about.donorsLinkText": "donors",
"about.donateLinkText": "donations page", "about.donateLinkText": "here",
"about.donateButton": "Donate" "about.donateButton": "Donate"
} }

File diff suppressed because one or more lines are too long

View file

@ -1,89 +0,0 @@
const SeleniumHelper = require('../selenium-helpers.js');
const helper = new SeleniumHelper();
var tap = require('tap');
const test = tap.test;
const webdriver = require('selenium-webdriver');
const driver = helper.buildDriver('www-smoke test-login-failures');
const {
findByCss,
clickCss
} = helper;
var until = webdriver.until;
var username = process.env.SMOKE_USERNAME;
var password = process.env.SMOKE_PASSWORD;
var rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
var url = rootUrl + '/users/' + username;
tap.plan(3);
tap.tearDown(function () {
driver.quit();
});
tap.beforeEach(function () {
return driver.get(url);
});
test('Trying to sign in with no password using scratchr2 navbar', t => {
var nonsenseusername = Math.random().toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
clickCss('.dropdown-toggle')
.then(() => findByCss('form#login input#login_dropdown_username'))
.then((element) => element.sendKeys(nonsenseusername))
.then(() => clickCss('form#login button'))
.then(() => findByCss('form#login .error'))
.then((element) => {
driver.wait(until.elementIsVisible(element));
return element;
})
.then((element) => element.getText())
.then((text) => t.match(text, 'This field is required',
'"This field is required" error should be displayed'))
.then(() => t.end());
});
test('Trying to sign in with the wrong username using scratchr2 navbar', t => {
var nonsenseusername = Math.random().toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
clickCss('.dropdown-toggle')
.then(() => findByCss('form#login input#login_dropdown_username'))
.then((element) => element.sendKeys(nonsenseusername))
.then(() => findByCss('form#login input.wide.password'))
.then((element) => element.sendKeys(password))
.then(() => clickCss('form#login button'))
.then(() => findByCss('form#login .error'))
.then((element) => {
driver.wait(until.elementIsVisible(element));
return element;
})
.then((element) => element.getText())
.then((text) => t.match(text, 'Incorrect username or password.',
'"Incorrect username or password" error should be displayed'))
.then(() => t.end());
});
test('Trying to sign in with the wrong password using scratchr2 navbar', t => {
clickCss('.dropdown-toggle')
.then(() => findByCss('form#login input#login_dropdown_username'))
.then((element) => element.sendKeys(username))
.then(() => findByCss('form#login input.wide.password'))
.then((element) => element.sendKeys('nonsensepassword'))
.then(() => clickCss('form#login button'))
.then(() => findByCss('form#login .error'))
.then((element) => {
driver.wait(until.elementIsVisible(element));
return element;
})
.then((element) => element.getText())
.then((text) => t.match(text, 'Incorrect username or password.',
'"Incorrect username or password" error should be displayed'))
.then(() => t.end());
});

View file

@ -1,58 +0,0 @@
/*
* Checks the behavior of the search interface
*/
require('chromedriver');
const seleniumWebdriver = require('selenium-webdriver');
const SeleniumHelper = require('../selenium-helpers.js');
const helper = new SeleniumHelper();
const {
urlMatches
} = helper;
const tap = require('tap');
const test = tap.test;
// Set test url through environment variable
const rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
const searchBaseUrl = `${rootUrl}/search/`;
// chrome driver
const driver = helper.buildDriver('www-search test_search');
tap.plan(3);
tap.tearDown(function () {
driver.quit();
});
tap.beforeEach(function () {
return driver.get(searchBaseUrl);
});
test('Search escapes spaces', function (t) {
const searchInput = driver.findElement(seleniumWebdriver.By.name('q'));
searchInput.sendKeys('Test search string', helper.getKey('ENTER')).then(function () {
urlMatches(/^.*\?q=Test%20search%20string$/)
.then(() => t.end());
});
});
test('Search escapes symbols', function (t) {
const searchInput = driver.findElement(seleniumWebdriver.By.name('q'));
searchInput.sendKeys('100% pen', helper.getKey('ENTER')).then(function () {
urlMatches(/^.*\?q=100%25%20pen$/)
.then(() => t.end());
});
});
test('Switching to studios maintains search string', function (t) {
const searchInput = driver.findElement(seleniumWebdriver.By.name('q'));
searchInput.sendKeys('100% pen', helper.getKey('ENTER')).then(function () {
const studiosTab = driver.findElement(seleniumWebdriver.By.xpath(
'//a/li/span[contains(text(),"Studios")]'));
studiosTab.click().then(function () {
urlMatches(/^.*\?q=100%25%20pen$/)
.then(() => t.end());
});
});
});

View file

@ -1,68 +0,0 @@
/*
* Tests stats page according to smoke-tests at:
*
* https://github.com/LLK/scratchr2/wiki/Smoke-Testing-Test-Cases
*
*/
const SeleniumHelper = require('../selenium-helpers.js');
const helper = new SeleniumHelper();
var tap = require('tap');
const test = tap.test;
const driver = helper.buildDriver('www-smoke test_statistics_page');
const {
clickText,
findByXpath,
findByCss
} = helper;
tap.plan(2);
tap.tearDown(function () {
driver.quit();
});
tap.beforeEach(function () {
/*
* load the page with the driver
* note that for now this is not testable on Staging,
* so I left it pointing to Production -
* we can at least use it post-deploy.
*
* var stagingURL = 'https://scratch.ly/statistics';
*/
var productionURL = 'https://scratch.mit.edu/statistics';
return driver.get(productionURL);
});
test('check that Monthly Activity Trends title is present & correct', t => {
var chartTitle = 'Monthly Activity Trends';
findByCss('div.box-head h3')
.then((element) => element.getText('h3'))
.then((text) => t.equal(text, chartTitle, 'chart title should be Monthly Activity Trends'))
.then(() => t.end());
});
test('check that Monthly Activity Trends chart > New Projects label is toggleable', t => {
var classXpath = `(//div[@id="activity_chart"]/*[name()='svg']/*[name()='g']/*[name()='g']/*` +
`[name()='g'])[4]/*[name()='g']/*[name()='g']/*[name()='g']`;
findByXpath(classXpath)
.then((element) => element.getAttribute('class'))
.then((classtext) => t.equal(classtext, 'nv-series', 'by default, New Projects should be enabled'))
.then(() => clickText('New Projects'))
.then(() => findByXpath(classXpath))
.then((element) => element.getAttribute('class'))
.then((classtext) => t.equal(
classtext,
'nv-series nv-disabled',
'when clicked, New Projects should be disabled'
))
.then(() => clickText('New Projects'))
.then(() => findByXpath(classXpath))
.then((element) => element.getAttribute('class'))
.then((classtext) => t.equal(classtext, 'nv-series', 'when clicked again, New Projects should be enabled'))
.then(() => t.end());
});

View file

@ -40,6 +40,7 @@ let profileComment = buildNumber + ' profile';
let studioComment = buildNumber + ' studio'; let studioComment = buildNumber + ' studio';
let projectReply = projectComment + ' reply'; let projectReply = projectComment + ' reply';
let profileReply = profileComment + ' reply';
let studioReply = studioComment + ' reply'; let studioReply = studioComment + ' reply';
if (remote) { if (remote) {
@ -284,6 +285,24 @@ describe('comment tests', async () => {
await expect(commentVisible).toBe(true); await expect(commentVisible).toBe(true);
}); });
test('profile reply to comment', async () => {
await driver.get(profileUrl);
// find the comment and click reply
let commentXpath = `//div[contains(text(), "${profileComment}")]/..`;
await clickXpath(commentXpath + '//a[@class = "reply"]');
// select reply box and type reply
let replyComposeBox = await findByXpath(commentXpath + '//textArea');
await replyComposeBox.sendKeys(profileReply);
// click post
await clickXpath(commentXpath + '//a[contains(text(), "Post")]');
// reload the page step has been skipped because caching causes failure
// The reply wasn't findable by xpath after several attempts, but it seems
// better to have this much of a test
});
test('studio: reply to comment', async () => { test('studio: reply to comment', async () => {
await driver.get(studioUrl); await driver.get(studioUrl);

View file

@ -0,0 +1,63 @@
// These tests do not sign in with a user
const SeleniumHelper = require('./selenium-helpers.js');
const {
buildDriver,
clickXpath,
findByXpath,
getKey
} = new SeleniumHelper();
let remote = process.env.SMOKE_REMOTE || false;
let rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
if (remote){
jest.setTimeout(60000);
} else {
jest.setTimeout(20000);
}
let driver;
describe('www-integration search', () => {
beforeAll(async () => {
driver = await buildDriver('www-integration search');
});
beforeEach(async () => {
await driver.get(rootUrl);
});
afterAll(async () => await driver.quit());
test('search converts spaces', async () => {
let searchBar = await findByXpath('//div[contains(@class, "search-wrapper")]/div/input');
await searchBar.sendKeys('Test search string' + getKey('ENTER'));
// check url
let url = await driver.getCurrentUrl();
await expect(url).toMatch(/^.*\?q=Test%20search%20string$/);
});
test('Search escapes symbols', async () => {
let searchBar = await findByXpath('//div[contains(@class, "search-wrapper")]/div/input');
await searchBar.sendKeys('100% pen' + getKey('ENTER'));
// check url
let url = await driver.getCurrentUrl();
await expect(url).toMatch(/^.*\?q=100%25%20pen$/);
});
test('Switching to studios maintains search string', async () => {
let searchBar = await findByXpath('//div[contains(@class, "search-wrapper")]/div/input');
await searchBar.sendKeys('100% pen' + getKey('ENTER'));
// switch to studios tab
clickXpath('//a/li/span[contains(text(),"Studios")]');
// check url
let url = await driver.getCurrentUrl();
await expect(url).toMatch(/^.*\?q=100%25%20pen$/);
});
});

View file

@ -199,6 +199,10 @@ class SeleniumHelper {
return false; return false;
} }
async waitUntilVisible (element, driver) {
await driver.wait(until.elementIsVisible(element));
}
} }
module.exports = SeleniumHelper; module.exports = SeleniumHelper;

View file

@ -7,7 +7,9 @@ const {
findByXpath, findByXpath,
clickXpath, clickXpath,
clickButton, clickButton,
buildDriver buildDriver,
signIn,
waitUntilVisible
} = new SeleniumHelper(); } = new SeleniumHelper();
let username = process.env.SMOKE_USERNAME; let username = process.env.SMOKE_USERNAME;
@ -30,6 +32,10 @@ describe('www-integration sign-in-and-out', () => {
driver = await buildDriver('www-integration sign-in-out'); driver = await buildDriver('www-integration sign-in-out');
}); });
afterAll(async () => {
await driver.quit();
});
describe('sign in', () => { describe('sign in', () => {
afterEach(async () => { afterEach(async () => {
await driver.get(wwwURL); await driver.get(wwwURL);
@ -71,14 +77,7 @@ describe('www-integration sign-in-and-out', () => {
describe('sign out', () => { describe('sign out', () => {
beforeEach(async () => { beforeEach(async () => {
await driver.get(wwwURL); await driver.get(wwwURL);
await clickXpath('//li[@class="link right login-item"]'); await signIn(username, password, driver);
let name = await findByXpath('//input[@id="frc-username-1088"]');
await name.sendKeys(username);
let word = await findByXpath('//input[@id="frc-password-1088"]');
await word.sendKeys(password);
await driver.sleep(500);
await clickXpath('//button[contains(@class, "button") and ' +
'contains(@class, "submit-button") and contains(@class, "white")]');
await driver.sleep(500); await driver.sleep(500);
}); });
@ -101,8 +100,61 @@ describe('www-integration sign-in-and-out', () => {
}); });
afterAll(async () => { describe('login failures', async () => {
await driver.quit(); test('sign in with no password in Scratchr2', async () => {
let nonsenseUsername = Math.random().toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
await driver.get(scratchr2url);
await clickXpath('//li[@class="sign-in dropdown"]/span');
let name = await findByXpath('//input[@id="login_dropdown_username"]');
await name.sendKeys(nonsenseUsername);
await clickButton('Sign in');
// find error
let error = await findByXpath('//form[@id="login"]//div[@class="error"]');
let errorText = await error.getText();
await expect(errorText).toEqual('This field is required.');
});
test('sign in with wrong username', async () => {
let nonsenseUsername = Math.random().toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
await driver.get(scratchr2url);
await clickXpath('//li[@class="sign-in dropdown"]/span');
let name = await findByXpath('//input[@id="login_dropdown_username"]');
await name.sendKeys(nonsenseUsername);
let word = await findByXpath('//input[@name="password"]');
await word.sendKeys(password);
await clickButton('Sign in');
// find error
let error = await findByXpath('//form[@id="login"]//div[@class="error"]');
await waitUntilVisible(error, driver);
let errorText = await error.getText();
await expect(errorText).toEqual('Incorrect username or password.');
});
test('sign in with wrong password', async () => {
let nonsensePassword = Math.random().toString(36)
.replace(/[^a-z]+/g, '')
.substr(0, 5);
await driver.get(scratchr2url);
await clickXpath('//li[@class="sign-in dropdown"]/span');
let name = await findByXpath('//input[@id="login_dropdown_username"]');
await name.sendKeys(username);
let word = await findByXpath('//input[@name="password"]');
await word.sendKeys(nonsensePassword);
await clickButton('Sign in');
// find error
let error = await findByXpath('//form[@id="login"]//div[@class="error"]');
await waitUntilVisible(error, driver);
let errorText = await error.getText();
await expect(errorText).toEqual('Incorrect username or password.');
});
}); });
}); });

View file

@ -0,0 +1,66 @@
// these tests do not sign in as a user
const SeleniumHelper = require('./selenium-helpers.js');
const {
buildDriver,
clickText,
containsClass,
findByXpath
} = new SeleniumHelper();
let remote = process.env.SMOKE_REMOTE || false;
let rootUrl = process.env.ROOT_URL || 'https://scratch.ly';
let statisticsPage = rootUrl + '/statistics';
if (remote) {
jest.setTimeout(60000);
} else {
jest.setTimeout(10000);
}
let driver;
describe('www-integration statistics page', async () => {
beforeAll(async () => {
driver = await buildDriver('www-integration statistics page');
});
beforeEach(async () => {
await driver.get(statisticsPage);
});
afterAll(async () => await driver.quit());
test('check Monthly Activity Trends title', async () => {
let chartTitle = await findByXpath('//div[contains(@class, "box0")]//h3');
let chartTitleText = await chartTitle.getText();
await expect(chartTitleText).toBe('Monthly Activity Trends');
});
test('New Projects label on first chart defaults to selected', async () => {
let toggleXpath = `(//div[@id="activity_chart"]/*[name()='svg']/*[name()='g']/*[name()='g']/*` +
`[name()='g'])[4]/*[name()='g']/*[name()='g']/*[name()='g']`;
let newProjectsToggle = await findByXpath(toggleXpath);
let toggleState = await containsClass(newProjectsToggle, 'nv-disabled');
await expect(toggleState).toBe(false);
});
test('New Projects label on first chart can be toggled', async () => {
let toggleXpath = `(//div[@id="activity_chart"]/*[name()='svg']/*[name()='g']/*[name()='g']/*` +
`[name()='g'])[4]/*[name()='g']/*[name()='g']/*[name()='g']`;
let newProjectsToggle = await findByXpath(toggleXpath);
// toggle off New Projects
await clickText('New Projects');
let toggleState = await containsClass(newProjectsToggle, 'nv-disabled');
await expect(toggleState).toBe(true);
// toggle New Projects on again
await clickText('New Projects');
toggleState = await containsClass(newProjectsToggle, 'nv-disabled');
await expect(toggleState).toBe(false);
});
});