I am exploring tools I can use for automated Accessibility Testing and wanted to try axe-core with TestCafe. I am an advocate of TestCafe, I love that is a lightweight tool and doesn't have dependencies on WebDriver. The docs are great and the scripting is easy.
I have however found that #testcafe-community/axe and its predecessor axe-testcafe do not report all violations while axe-core with selenium and axe-webdriverjs do. For example, running with axe-webdriverjs, I have the following code and resulting output showing the violations of a localhost page I am checking -
Code:
var AxeBuilder = require('axe-webdriverjs');
var WebDriver = require('selenium-webdriver');
const path = require('path');
process.env.PATH = path.resolve(`__dirname/../WebDriver/bin/Firefox/0.29.1`) + ':' + process.env.PATH;
var driver = new WebDriver.Builder()
.forBrowser('firefox')
.build();
driver
//.get('https://dequeuniversity.com/demo/mars/')
.get('http://localhost:3000')
.then(function() {
AxeBuilder(driver).analyze(function(err, results) {
if (err) {
// Handle error somehow
}
console.log(results.violations);
});
});
Output:
> axe-webdriverjs-tests#1.0.0 test1 /Users/nabeen.jamal/gitlab.com/notifications-service/text-messaging-application/tma-test/app/axe-webdriverjs-tests
> node test/axe.test1.js
[
{
description: 'Ensures all page content is contained by landmarks',
help: 'All page content must be contained by landmarks',
helpUrl: 'https://dequeuniversity.com/rules/axe/3.5/region?application=webdriverjs',
id: 'region',
impact: 'moderate',
nodes: [ [Object], [Object] ],
tags: [ 'cat.keyboard', 'best-practice' ]
}
]
Using #testcafe-community/axe and following the 'How to use' on the project github page (https://github.com/testcafe-community/axe), I have the following code and resulting output which shows no violations of the same localhost page.
Code:
import { checkForViolations } from '#testcafe-community/axe';
fixture `TestCafe tests with Axe`
//.page `http://example.com`;
.page `http://localhost:3000`;
test('Automated accessibility testing', async t => {
// do stuff on your page
await checkForViolations(t);
});
Output:
nabeen.jamal#DEM-C02DFG1UMD6M axe-testcafe-tests % npx testcafe --config-file cfg/testcaferc.json chrome src/test1.js
(node:88006) ExperimentalWarning: Conditional exports is an experimental feature. This feature could change at any time
(node:88006) ExperimentalWarning: Package name self resolution is an experimental feature. This feature could change at any time
Running tests in:
- Chrome 90.0.4430.212 / macOS 10.15.7
TestCafe tests with Axe
✓ Automated accessibility testing
1 passed (0s)
As the output shows, the #testcafe-community/axe test passes and shows no violations while the axe-webdriverjs (and axe-core with selenium) shows the violation about "all page content contained by landmarks".
Is this a limitation in #testcafe-community/axe, or do you have to specify the rules in the options parameter of axe.run for it to carry out the checks on the rendered content of the loaded page?
The documentation for axe-core states that you need to specify which rules you intend to test against using axe.run options.
Landmarks are discussed in WCAG 1.3.6., which is a "Level AAA" item. It appears that axe-core is only capable of testing against "Level A" and "Level AA." In your example, the item is not listed by the tool as a WCAG failure, but rather a best-practices recommendation. This may be why it isn't showing up in your other tools.
If you can easily implement this recommendation, then I'd say go ahead and do it. If not, I wouldn't let something like this stop my code from going into production. Landmarks are nice-to-have, but it's far more important that you meet all "Level A" requirements and as many "Level AA" requirements as you reasonably can.
It's worth noting that any automated accessibility testing tool is nothing more than a starting point for manual evaluation. These tools often generate tons of false positives (and sometimes miss important things!) because it's often not possible to algorithmically determine whether something is genuinely useful to human visitors.
I've also seen pages/apps that pass automated tools with no errors (Wave, Axe, etc.), but they are completely impossible to use with assistive technology.
I'm not 100% certain how, but my tests using axe-testcafe and #testcafe-community/axe are now showing the violation -
Running tests in:
- Chrome 90.0.4430.212 / macOS 10.15.7
TestCafe tests with Axe
✓ Verify Welcome Page loads properly
✖ Automated accessibility testing
1) AssertionError: 1 violations found:
1) All page content must be contained by landmarks
* https://dequeuniversity.com/rules/axe/3.5/region?application=axeAPI
* cat.keyboard, best-practice
* moderate
* region
"#global-cookie-message"
".app-phase-banner"
: expected false to be truthy
Browser: Chrome 90.0.4430.212 / macOS 10.15.7
67 |const checkForViolations = async (t, context, options) => {
68 | const { error, results } = await axeCheck(t, context, options);
69 |
70 | await t.expect(error).notOk();
71 |
> 72 | await t.expect(results.violations.length === 0).ok(createReport(results.violations));
73 |}
74 |
75 |
76 |module.exports = {
77 | runAxe,
at checkForViolations
(/Users/nabeen.jamal/gitlab.com/notifications-service/text-messaging-application/tma-test/app/axe-testcafe-tests/node_modules/#testcafe-community/axe/index.js:72:53)
1/2 failed (1s)
I didn't have to specify the rules in the options parameter to axe.run - I did do so, but with or without, the violation does now get reported.
I did however uninstall and reinstall the node packages and I think the version of axe-core is different to what I had previously. Here are my dependencies and the versions in my package.json that work for me -
{
"name": "axe-testcafe-tests",
"version": "1.0.0",
"description": "axe-core and TestCafe testware to cover Accesibility Testing of the TMA App",
"main": "index.js",
"dependencies": {
"testcafe": "^1.14.2"
},
"devDependencies": {
"#testcafe-community/axe": "^3.5.0",
"axe-core": "^3.5.5",
"axe-testcafe": "^3.0.0"
},
<-- snip -->
Thank you again #Josh for your help. Perhaps this might help others.
Related
Creating a friend a site using Gatsby 4.0 and thought I would use the material UI template. looks nice and works in develop.
I go to build and I get the following errors, I presume its the material UI plugin with using the withStyles function but I am a noob and I can't find a solution online (If I find, at least it's recorded):
failed Building static HTML for pages - 2.794s
ERROR #95312
"document" is not available during server side rendering.
See our docs page for more info on this error: https://gatsby.dev/debug-html
72 | var _options = options,
73 | _options$window = _options.window,
74 | window = _options$window === void 0 ? document.defaultView : _options$window;
| ^
75 | var globalHistory = window.history;
76 |
77 | function getIndexAndLocation() {
WebpackError: ReferenceError: document is not defined (from plugin: gatsby-plugin-material-ui)
index.js:74
[leighton]/[history]/index.js:74:1
index.js:82
[leighton]/[react-router-dom]/index.js:82:26
index.js:22
[leighton]/[decode-uri-component]/index.js:22:1
index.js:25
[leighton]/[decode-uri-component]/index.js:25:1
index.js:31
[leighton]/[decode-uri-component]/index.js:31:1
index.js:30
[leighton]/[decode-uri-component]/index.js:30:4
index.js:41
[leighton]/[decode-uri-component]/index.js:41:1
gatsby-ssr.js:33
[leighton]/[gatsby-plugin-material-ui]/gatsby-ssr.js:33:47
api-runner-ssr.js:92
leighton/.cache/api-runner-ssr.js:92:28
static-entry.js:266
leighton/.cache/static-entry.js:266:11
dev-404-page.js:15
leighton/.cache/dev-404-page.js:15:11
WebpackError: ReferenceError: document is not defined (from plugin:
gatsby-plugin-material-ui)
The source of the issue is in the SSR (Server-Side Rendering). Summarizing a lot, when your un gatsby develop the code is interpreted by the browser, where you can play with window, document, and other global objects. However, gatsby build runs in the Node server where there's no window or document because has not even been created yet. That's why works in development and not in build mode.
This issue can by easily bypassed by adding the following condition before the usage of those global objects:
if (typeof window !== 'undefined'){
// code here
}
Or wrapping the code in a useEffect with empty deps ([]). This will ensure that the DOM tree is loaded thus there's a window (or document) available.
In your case, without any code samples or implementation of gatsby-plugin-material-ui it's impossible to know where's the code source of the issue.
I am getting 403 errors with sp-rest-proxy. I was originally using the “User Credentials” strategy which allowed me to GET data, but not POST it. So now I’m am trying the “Addin only permissions”. My I.T. team was able get the app registered for me. but I am still receiving the below error now even with GET.
Error Details:
{
"readyState": 4,
"responseText": "{\"error\":{\"code\":\"-2147024891, System.UnauthorizedAccessException\",\"message\":{\"lang\":\"en-US\",\"value\":\"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))\"}}}",
"responseJSON": {
"error": {
"code": "-2147024891, System.UnauthorizedAccessException",
"message": {
"lang": "en-US",
"value": "Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"
}
}
},
"status": 403,
"statusText": "Forbidden"
}
Things I suspect I messed up on:
I strongly think its my server/private config I have the following…
const RestProxy = require('sp-rest-proxy');
const settings = {
configPath: './config/private.json',
port: 8081,
};
const restProxy = new RestProxy(settings);
restProxy.serve();
and private (not the actual values I am using expect for "strategy" )
{
"siteUrl": "https://ORGANIZTION.sharepoint.com",
"strategy": "OnlineAddinOnly",
"clientId": "0000000-000000-000000-0000-00000000",
"clientSecret": "000000000000000000000000000000",
"realm": "00000-0000-0000-0000-000000"
}
I couldn’t find much on the “strategy” value on the sp-rest-proxy or the node-sp-auth side of the documentation. I can assume its OnlineAddinOnly but I’m not able to find the specific syntax for what possible values this attribute expects. I also noticed that the “clientSecret” is changing once I run the server, I assume this is an intentional encryption.
During the App registration phase (step 5 of this https://github.com/s-KaiNet/node-sp-auth/wiki/SharePoint%20Online%20addin%20only%20authentication) I had the IT folk set the “right” attribute in AppPermissionRequests to “Write” instead “FullControl”, I noticed that “FullControl” seems to be used in most example though I wasn’t sure if it was required. Can anyone confirm that?
[Edit: confirmed this is not the issue by setting this to FullControl]
Intention:
I am trying to build an internal data management tool that only needs to work on localhost to get manipulate and replace json files in my teams SharePoint. (just in a nice way so that non-coders can do this). The “sp-rest-proxy” library seems to be what I need to implement the REST API effectively in react.
As far as I know, SharePoint app-only access is disabled by default. You need to ask your administrator to enable it by running the following command:
set-spotenant -DisableCustomAppAuthentication $false
The answer likely in the XML AppPermissionRequests. The creator of the library was able to point me to a better example and I had noticed some differences we had a different scope value and no AllowAppOnlyPolicy adding these seems to have fixed most of the issue. I am able to confirm that I can now do GET.
I am still having issues with GetFolderByServerRelativeUrl and using the to add/replace files but I am not sure that is related and will treat it as a separate issue as it may not be related to sp-rest-proxy or node-sp-auth
the correct AppPermissionRequests XML should be this ->
and as #Michael Han_MSFT mentioned you should ensure that DisableCustomAppAuthentication is set to false
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />
</AppPermissionRequests>
I've inherited a simple site with staging and production projects living on Google App Engine. Yesterday made a simple deploy to staging (using CircleCI), the first deploy since January. Since then the site won't load and the logs show an exception we haven't had before:
"Cannot read property 'parsePath' of undefined" when trying to go to the home page at: /
Our code does not make any call to 'parsePath', so it must be some underlying machinery.
I reverted the code change and re-pushed the staging branch with the code that's been live since January (and is live and error-free right now in production), deploy was successful, but the same symptom is there still in staging! (Needless to say, we can't deploy anything to production until we know what the heck is going on)
I've been looking through the circleCI deploy logs for clues- one difference is during the "gcloud auth activate-service-account" step, it wasn't able to update the compute/zone property (but the build still succeeded):
Updated property [core/project].
WARNING: You do not appear to have access to project [veryloudstatic] or it does not exist.
Updated property [compute/zone].
What should I be looking at on the GAE side? Has anyone seen this exception before, or know enough about how GAE works to suggest places to troubleshoot? We haven't made any changes to these GAE projects in the past few months, so I'm wondering if some internal updates could be the issue?
Cannot read property 'parsePath' of undefined
Expand all | Collapse all {
insertId: "owonpfihz4box5kp7"
labels: {
appengine.googleapis.com/instance_name: "aef-default-20190620t195308-lsn2"
compute.googleapis.com/resource_id: "2700574583511472701"
compute.googleapis.com/resource_name: "b6282fd5dc84"
compute.googleapis.com/zone: "us-central1-f"
}
logName: "projects/veryloudstatic/logs/appengine.googleapis.com%2Fstderr"
receiveTimestamp: "2019-06-21T13:53:47.746443513Z"
resource: {
labels: {
module_id: "default"
project_id: "veryloudstatic"
version_id: "20190620t195308"
}
type: "gae_app"
}
textPayload: "Cannot read property 'parsePath' of undefined
"
timestamp: "2019-06-21T13:53:45Z"
}
35.233.167.246 - "GET /" 500 148 "-" "GoogleStackdriverMonitoring-UptimeChecks(https://cloud.google.com/monitoring)"
Expand all | Collapse all {
httpRequest: {
latency: "0.166s"
referer: "-"
remoteIp: "35.233.167.246"
requestMethod: "GET"
requestUrl: "/"
responseSize: "148"
status: 500
userAgent: "GoogleStackdriverMonitoring-UptimeChecks(https://cloud.google.com/monitoring)"
}
insertId: "28alo0fexgmee"
jsonPayload: {…}
labels: {…}
logName: "projects/veryloudstatic/logs/appengine.googleapis.com%2Fnginx.request"
receiveTimestamp: "2019-06-21T13:53:47.746443513Z"
resource: {…}
timestamp: "2019-06-21T13:53:45.536Z"
trace: "projects/veryloudstatic/traces/5190f7942330e15370ff65d1c79c5963"
}
Without more of a stack trace its hard to tell, but check your dependency versions if there are any. An underlying dependency may have updated. Make sure to check both your app code and the CircleCI base image.
I am trying to perform unit testing and integration testing for a React Native application. When running yarn test --coverage several of my test suites fail to run because of the tcomb-form-native library.
I receive this specific error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import t from "./lib";
SyntaxError: Unexpected identifier
13 | // import { gray } from 'ansi-colors';
14 |
> 15 | import t from 'tcomb-form-native';
| ^
16 |
17 | const Form = t.form.Form;
18 |
at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
at Object.<anonymous> (screens/ReservationScreen.js:15:1)
I updated the package.json file following the Tests section from the library's GitHub, https://github.com/gcanti/tcomb-form-native, but continue to get the same error.
I'm confused by this line from the tcomb-form-native ReadMe Tests description:
"ios.js" <<<<<<<<<<<< this needs to be defined!
I created the React Native app using Expo so I don't have an ios.js file. The only difference under the "jest": from the example code in the GitHub is that I also have "preset": "jest-expo", defined.
What changes do I need to make to my package.json file or my test suites in order for my test suites to run? (They don't have to pass, just simply run.)
Edit:
I tried adding the following code to package.json based on the top answer from https://github.com/gcanti/tcomb-form-native/issues/443:
"transformIgnorePatterns": [
"node_modules/(?!react-native|tcomb-form-native)"
]`
I added the code without the original suggested edits from the library's GitHub ReadMe and added it IN ADDITION to the suggested edits. I am still receiving SyntaxError: Unexpected identifier when I run tests.
Edit #2:
I changed changed import t from 'tcomb-form-native'; to var t = require('tcomb-form-native'); and I'm still receiving SyntaxError: Unexpected identifier.
When compiling a React and Redux application with Webpack and Babel I get:
Uncaught TypeError: Cannot assign to read only property '__esModule' of #<Object>
In some older browsers (<= Chrome 1, Android 4, Safari 5).
This issue seems to stem from redux and react-redux outputting the line exports.__esModule = true; in the lib build but my application using Object.defineProperty instead (because they build loosely and I do not).
Two solutions are:
Building my application in loose mode also.
Importing react-redux/src and redux/src and building it with the same .babelrc as the application (everything is not loose).
As long as they are consistent and both:
Object.defineProperty(exports, "__esModule", {
value: true
});
and exports.__esModule = true; do not co-exist in my output, everything works.
My question is, what is the right solution? Why does this only affect older browsers? And why do they conflict?
Here is a similar question.
Object.defineProperty is broken on some Android 4 stock browser versions and probably other browsers that made use of a buggy implementation in Webkit.
Check this bug report
and and this other one reported to the chromium project.
The good news is you can apply this polyfill to fix the problem.
To make thing easy, you can simply copy and paste that polyfill on a <script> tag before your bundle.
This will fix your issues.
My guess is, you need to install babel-plugin-add-module-exports and in your .babelrc register this plugin:
"plugins": [
"babel-plugin-add-module-exports"
]
For more information visit this website.
In my case, I solved to add babel-register library in entry points.
In webpack.config.js (Webpack 1.x version of configuration)
// As is
entry: {
main: 'index.js'
},
// To be
entry: {
main: ['babel-register', 'index.js']
},
We met this problem on Android 4.0 and currently we cannot cut the support for Android 4.0.
For webpack 1.0, just set loose: true when you are using babel-preset-env.
However for Webpack 2, loose mode can't resolve this problem.
Finally, we found this trick, a little ugly.
// client_patch.js, For Android 4.0
var defineProperty = Object.defineProperty;
Object.defineProperty = function (exports, name) {
if (name === '__esModule') {
exports[name] = true;
return;
}
return defineProperty.apply(this, arguments);
};
And in your webpack config file.
// webpack.config.js
entry: {
main: [
path.resolve(__dirname, 'client_patch.js'),
'index.js'
]
}