-
Notifications
You must be signed in to change notification settings - Fork 125
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
feat(qunit-dom): Ability to add custom dom
handlers
#2101
Conversation
e21dc51
to
8384d74
Compare
Continuing this discussion after speaking with @mansona and the tooling team today: The working proposalIt sounds like we're going to iterate on this to allow the configuration of only a single assertion handler, and then will expose the built-in assertion handler so callers can wrap it, so the unit test's custom handler would look like: import { qunitDomAssertionHandler } from '../assertions';
const customHandler: DOMAssertionsHandler<u32> = {
findElements(target: u32, rootElement: RootElement) {
if (typeof target === 'number') {
return { ok: true, value: toArray(rootElement.querySelectorAll(`[data-id="${target}"]`)) };
} else {
return qunitDomAssertionHandler.findElements(target, rootElement);
}
},
findElement(target: u32, rootElement: RootElement) {
if (typeof target === 'number') {
return { ok: true, value: rootElement.querySelector(`[data-id="${target}"]`) };
} else {
return qunitDomAssertionHandler.findElement(target, rootElement);
}
},
description(target: u32) {
if (target >= 200) {
return { ok: true, value: `data-id=${target}` };
} else if (target <= 100) {
return { ok: true, value: target };
} else {
return qunitDomAssertionHandler.description(target);
}
},
}; So then the integration would involve making import { setup } from 'qunit-dom';
setup(QUnit.assert, {
customHandler: /* something goes here */
}); My open questionMy question is what is the I see a couple of options: The app/blueprintThis would involve modifying the blueprint to have the import {
setup,
qunitDomAssertionHandler,
type DOMAssertionsHandler,
} from 'qunit-dom';
import {
isDescriptor,
resolveDOMElement,
resolveDOMElements,
resolveDescription,
type IDOMElementDescriptor,
} from 'dom-element-descriptors';
type Target =
| IDOMElementDescriptor
| Parameters<(typeof qunitDomAssertionHandler)['findElement']>[0];
const customHandler: DOMAssertionsHandler<Target> = {
findElement(target, rootElement) {
return isDescriptor(target)
? { ok: true, value: resolveDOMElement(target) }
: qunitDomAssertionHandler.findElement(target, rootElement);
},
findElements(target, rootElement) {
return isDescriptor(target)
? { ok: true, value: Array.from(resolveDOMElements(target)) }
: qunitDomAssertionHandler.findElements(target, rootElement);
},
description(target) {
return isDescriptor(target)
? { ok: true, value: resolveDescription(target) || '' }
: qunitDomAssertionHandler.description(target);
},
};
setup(QUnit.assert, { customHandler }); We could improve the ergonomics of this by reorganizing the types a little, or perhaps by having the blueprint generate a separate file with the custom handler definition, but regardless, with this option we'd be adding a good deal of blueprint-generated code to applications.
|
It also looks like we'd need to add something like declare global {
interface Assert {
dom(target?: IDOMElementDescriptor, rootElement?: Element): DOMAssertions;
}
} where the integration happens in order to make the types actually work. They work in the unit test because it constructs a TestAssertions instance directly, but that has no impact on the global |
I've re-implemented the handler so the previous examples are out of date; especially since for both Typescript and overall experience we should keep only one instance of a handler as opposed to having a resolver pipeline.
That responsibility should fall upon anyone who's using the qunit-dom and wants to introduce a handler for different import { setup } from 'qunit-dom';
import { qunitDomAssertionHandler } from 'dom-element-descriptors';
setup(QUnit.assert, {
targetHandler: qunitDomAssertionHandler
}); However to my understanding that also requires the user to change their Alternatively, if the |
packages/qunit-dom/lib/assertions.ts
Outdated
@@ -28,11 +28,56 @@ type CSSStyleDeclarationProperty = keyof CSSStyleDeclaration; | |||
|
|||
type ActualCSSStyleDeclaration = Partial<Record<CSSStyleDeclarationProperty, unknown>>; | |||
|
|||
type FoundElement = Element | null; |
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 this isn't going to work? This allows findElements()
to return an array that could have a mix of Element
s and null
, which doesn't seem right. I see the built-in handler is currently returning [null] when it is passed a null
target, but this is causing a bug in matchesSelector()
and doesNotMatchSelector()
as the tests I added in #2107 demonstrate (if they were merged/copied into this branch).
I think findElements
needs to just return Element[]
, and we need to return []
in the target === null
case of findElements()
.
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 catch 👍
Okay, thanks for updating the code to the single-handler model! It looks to me like my above analysis still stands -- for Ember apps to be able to follow the RFC and use |
@bendemboski this is how I imagine an extension to work https://github.com/mainmatter/qunit-dom/pull/2101/files#diff-77d9a078396260d7903d558b1dd631f37cdc2ec889659452e7740a3d17549cd5R46 They define a wrapper around a Page-object users use external libraries already and that change could be relayed as some migration guide. I don't think that |
@BobrImperator and @mansona that makes sense in isolation, but I'm still not understanding your full proposal for how this is used to implement the RFC. In what project does the code that subclasses |
Whoever implements page-objects, or the Libraries such as |
@BobrImperator the idea behind Can you help me understand your reluctance to integrate it into |
@bendemboski Yes, my concern from the start was primarily another dependency we don't control control ourselves and the maintenance of it. Additionally However I see that we're going nowhere with the implementation I've made and I really don't want to keep on blocking you. |
@BobrImperator no worries -- especially with widely used projects like |
No description provided.