-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support 0-level assertion priorities on TestRun page #863
Conversation
client/components/common/queries.js
Outdated
@@ -0,0 +1,183 @@ | |||
import { gql } from '@apollo/client'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reviewers: I noticed quite some time ago, a LOT of the query params are often repeated. So much so that params are often missed in data update PRs, so I'm proposing to start writing the various individual component queries.js
files as a construction of these repeated fragments.
Using this PR as a chance to help visualize that potential change. It's already cut down TestRun/queries.js
by a significant amount. If this does cause significant clashes with any other floating PRs (or a proposal to do it differently), I'm happy to revert and make this more of a concentrated task by itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm down with this. Most fields don't impact query performance so it's totally fine to just query all of them every time. For fields that do impact performance, like tests on TestPlanVersions and testResults on TestPlanRuns, I think it should be divided into two fragments to make accidentally tanking your performance less likely to happen. Something like TEST_PLAN_RUN_FIELDS
and TEST_PLAN_RUN_TEST_RESULTS_FIELDS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think fields like renderableContent might be preferable to leave off, since they're extremely verbose and "specialty" for specific use cases. If it's there where it's not needed it will definitely make debugging responses harder.
We can manually add them where they're needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see that benefit, as well as some others, even in the mock testing area. For clarity though, the fields replaced by a fragment has the exact same fields as were listed before, so no additional (or unnecessary) fields just yet. But I do think there's a benefit to this approach, and an even greater benefit if that structure is set up properly.
So I'd rather to remove this proposed enhancement bit from these unrelated code changes and follow up in a separate issue so this enhancement can get it's own focused space.
server/scripts/import-tests/index.js
Outdated
@@ -53,7 +53,8 @@ Default use: | |||
const client = new Client(); | |||
|
|||
const ariaAtRepo = 'https://github.com/w3c/aria-at.git'; | |||
const ariaAtDefaultBranch = 'master'; | |||
// const ariaAtDefaultBranch = 'master'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be reverted before merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice trick!
server/graphql-schema.js
Outdated
Indicates if this assertion result needs to be ignored because it is included with | ||
a 0-level priority | ||
""" | ||
exclude: Boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If some assertions are not relevant, I don't think we should require users of the API to be responsible for detecting that and requiring them to pass in a special assertionResult with an "exclude" flag set to true. It feels like an example where complexity is escaping the abstraction. API consumers should only have to provide assertionResults which are relevant to the testResult.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in fe222f7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good thanks for addressing that!!
server/graphql-schema.js
Outdated
The same command can be ran during the same test, but in a different | ||
mode | ||
""" | ||
settings: String |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to make this an enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The values here won't be static. If the support.json
is updated with a new AT + settings (or just a new setting in general for a currently imported AT), and the auto-importer triggers, it will fail to query the relevant content if this is an enum of the settings
values we know of now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about calling this "atOperatingMode"? I have a couple of motivations for the suggestion. One is that since the word "settings" is plural it makes me suspicious that I'm dealing with something like a comma separated list. Another is that settings is quite a broad term, and are not obviously dealing specifically with the AT, for example it could be referring to operating system settings, browser settings, keyboard settings like holding the shift key, any kind of settings, and I think that's one of the things which is confusing me. I suggested "operatingMode" because I feel like "atMode" is a bit too restrictive a term.
Also, can you improve the documentation for this field? I think we should exhaustively list out all the values which are currently used, one by one. Also if you have a link to a specification listing all possible options, putting that here would be hugely helpful as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On settings > atOperatingMode request
I suggested "[atO]peratingMode" because I feel like "atMode" is a bit too restrictive a term.
Agreed, I can make that change.
... since the word "settings" is plural it makes me suspicious that I'm dealing with something like a comma separated list.
Note that eventually, this may happen. That's based on the spec request of AT_KEY-commands.csv > settings.
On documentation update request
Also, can you improve the documentation for this field? I think we should exhaustively list out all the values which are currently used, one by one.
Listing them out will require a change any time they're updated, which would be of an unknown frequency. That would make that bit of inline documentation irrelevant for a bit of time and I'm doubtful of how best that will be kept updated.
Also if you have a link to a specification listing all possible options, putting that here would be hugely helpful as well.
I don't but let's suggest updating the v2 Test Format Definition with a section on that and link there. Otherwise, the only spec for that is to check out each key in ats[].settings in support.json
, which isn't too easy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! I like what you did with the GraphQL fragments, you were able to delete a surprising amount of code, and that's definitely a good thing.
I feel quite strongly that we should not add a concept of inert assertionResults that API consumers must disable with an exclude flag. If an assertionResult is not relevant I feel like API consumers shouldn't need to provide anything or worry about it at all.
As for an alternate way to do it, one suggestion is that we add the ability to filter test assertions by mode.
It might be more involved to implement up front but I think it will be worth it make sure our abstractions are robust enough to shoulder the weight of all this complexity.
@alflennik agreed! I had the same concern when initially making this PR and was hoping to resolve it in a follow up task because of my assumption that further changes to the harness and TestRenderer would be required, which would conflict with already floating changes in that bit of work that would have been too mentally hard to track. Taking another look at it now (and with fresh thoughts 🙂), turns out that wasn't needed. fe222f7 should address this. |
Thanks for addressing my big piece of feedback! Also I followed up on the conversation about the settings field. |
…0 level assertions will be considered internally as 'EXCLUDE')
0b2f00a
to
635cf65
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing all the changes I requested! Also, big thanks for adding that branch with assertionExceptions populated, that was invaluable to make it easier to test this.
…test format version to also include (an empty) assertionExceptions so hashes will remain in sync; include utility introduced in #880
priority = 'SHOULD'; | ||
if (assertionPriority === 3) | ||
priority = 'MAY'; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a utility variable that maps these ints to these strings (which could also be enums). This would help centralize and lift the significance of these relationships which would be helpful for someone like me that was just editing `assertionExceptions`` on my local aria-at without fully understanding what the numbers meant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. There's the server/resolvers/helpers/convertAssertionPriority.js
file, which could be moved to a more appropriate location, and be expanded to something like:
const convertAssertionPriority = priority => {
if (priority === 0) return 'EXCLUDE';
if (priority === 'REQUIRED' || priority === 1) return 'MUST';
if (priority === 'OPTIONAL' || priority === 2) return 'SHOULD';
if (priority === 3) return 'MAY';
// ...
};
module.exports = convertAssertionPriority;
Would this support what you're thinking of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would work. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 3d1fbcb
client/components/TestRun/index.jsx
Outdated
})) | ||
assertionResults: assertionResults | ||
// All assertions are always being passed from the TestRenderer results, but in the instance where | ||
// there is a 0-priority exception, and id won't be provided and that cannot be saved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this taking advantage of a side effect or is this the strategy used for communicating that an assertion is excluded? It seems easy to misunderstand or forget. I would expect them to be passed prefiltered but I might be missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been some time now, so I'll have to look back into why exactly it was done that way. But from what I can remember, the TestRenderer
still technically requires the index of that excluded assertion to properly determine which assertions are which, but at some point. It definitely had to be removed before saving and those excluded ones had no ids. That was a part of fulfilling this request with 5c4ec6a.
Is this taking advantage of a side effect or is this the strategy used for communicating that an assertion is excluded?
So seems to be a bit of both.
This point in the code looks like the safest place to filter them out, as the single point before being passed to the server/db. The comment could be much clearer as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh okay. The background is helpful. I'll leave it to you as to whether you want to change the comment or address it any other way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in af9a5b0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am approving after our discussion in the two comment threads. I know that some temporary branch settings need to be reset before merging so I will pass this back to you with approval.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, @howard-e; this works as expected, so nothing blocking from me.
Note 1: This work is dependent on w3c/aria-at#1012 landing and any updated
client/resources
files here should be reviewed there.
That patch was recently merged, so I've left my comments here.
let assertionExceptions = json.output_assertions.map(each => each.assertionId); | ||
foundCommandInfo.assertionExceptions.split(' ').forEach(each => { | ||
let [priority, assertionId] = each.split(':'); | ||
const index = assertionExceptions.findIndex(each => each === assertionId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Array.prototype.indexOf
would be a bit more readable here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
priority = Number(priority); | ||
assertionExceptions[index] = priority; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under the assumption that "fewer mutable bindings is better", these statements could be combined to allow swapping the earlier let
for a const
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
}); | ||
// Preserve default priority or update with exception | ||
assertionExceptions = assertionExceptions.map((each, index) => | ||
isNaN(each) ? json.output_assertions[index].priority : each |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't the members of assertions
string values? Returning each
from a filter predicate suggests otherwise.
// Filter out assertionResults which were marked with a 0-priority exception | ||
.filter(assertion => { | ||
return !assertion.assertionExceptions?.some( | ||
e => | ||
scenario.commands.find( | ||
c => | ||
c.id === e.commandId && | ||
c.atOperatingMode === e.settings | ||
) && e.priority === 'EXCLUDE' | ||
); | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment doesn't seem to acknowledge the first half of the filter expression, making me wonder whether I understand what's going on here. Would it be accurate to say, "Filter out assertionResults for the current scenario which were marked with a 0-priority exception"?
Stylistically, I think that the closure nesting is reaching a point where it interferes with readability. While the in-line documentation you've suggested helps, breaking this logic out into a standalone function would afford us more room to describe what's going on, reduce the cognitive load (by formalizing the inputs), and limit distraction for folks seeking to understand createTestResultSkeleton
at a high level.
/**
* Determine whether a given assertion belongs to a given scenario and includes
* at least one exception with a given priority.
*
* @param {string} priority
* @param {Scenario} scenario
* @param {Assertion} assertion
*/
const hasExceptionWithPriority = (priority, scenario, assertion) => {
return assertion.assertionExceptions?.some(
e =>
scenario.commands.find(
c =>
c.id === e.commandId &&
c.atOperatingMode === e.settings
) && e.priority === priority
);
};
Then invoking like this:
.filter(assertion => !hasExceptionWithPriority('EXCLUDE', scenario, assertion))
I'm only sharing something concrete as a means to demonstrate my point; I'm not too concerned with the specific factoring. For instance, a more purpose-built function would simplify the callsite even further (though it might be difficult to name it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on this. I was able to take your suggestion and only apply minor changes, thanks! Done in bba8ad4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jugglinmike I appreciate your feedback on the aria-at related components. Sad that the PR was merged before but I can create a follow up PR there and request your review afterwards
let assertionExceptions = json.output_assertions.map(each => each.assertionId); | ||
foundCommandInfo.assertionExceptions.split(' ').forEach(each => { | ||
let [priority, assertionId] = each.split(':'); | ||
const index = assertionExceptions.findIndex(each => each === assertionId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed
priority = Number(priority); | ||
assertionExceptions[index] = priority; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
// Filter out assertionResults which were marked with a 0-priority exception | ||
.filter(assertion => { | ||
return !assertion.assertionExceptions?.some( | ||
e => | ||
scenario.commands.find( | ||
c => | ||
c.id === e.commandId && | ||
c.atOperatingMode === e.settings | ||
) && e.priority === 'EXCLUDE' | ||
); | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on this. I was able to take your suggestion and only apply minor changes, thanks! Done in bba8ad4
See w3c/aria-at#1008.
How To Run:
Note 1: This work is dependent on w3c/aria-at#1012 landing and any updated
client/resources
files here should be reviewed there.Note 2: This is using a sample example data made available by w3c/aria-at branch collection-0-priority-support-test. You can view the specifics of the change in the description of w3c/aria-at#1014.
Set
ariaAtDefaultBranch
inimport-tests/index.js
tocollection-0-priority-support-test
for testing purposes.NOTE: REVERT TEST BRANCH BEING IMPORTED IN
import-tests/index.js
BEFORE MERGING