-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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(auto-init): Fire event on mdcAutoInit complete #1012
feat(auto-init): Fire event on mdcAutoInit complete #1012
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! |
CLAs look good, thanks! |
Codecov Report
@@ Coverage Diff @@
## master #1012 +/- ##
=========================================
- Coverage 99.93% 99.9% -0.03%
=========================================
Files 68 69 +1
Lines 3276 3314 +38
Branches 403 409 +6
=========================================
+ Hits 3274 3311 +37
- Misses 2 3 +1
Continue to review full report at Codecov.
|
@yshterev Thanks for filing the PR. So here in the For firing event Test firing event Listen to fired event (FYI) Feel free to ping me back for further question and thanks again for being on it! |
@yeelan0319 The FakeComponent in I am not sure my test logic is very good. It relies on the first argument passed to the |
packages/mdc-auto-init/index.js
Outdated
Object.defineProperty(node, ctorName, { | ||
value: component, | ||
writable: false, | ||
enumerable: false, | ||
configurable: true, | ||
}); | ||
} | ||
|
||
if (component !== 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.
There might be multiple components initialize with mdc-auto-init
method and my original thought is each of them should have their own init:end
event.
If you are interested in just having one custom event about the whole auto-init end, maybe we shouldn't do that from a component level.
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.
Probably I got this wrong.
If each component emits its own init:end
event when done, how would you know when all of components are initialzied? Or maybe we can use combination of both? Each component can emit own event when initialized, like ComponentNameInit:End
and then 'MDCAutoInit:End' when all of them are initialized?
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 I understand correctly the original issue was regarding having a way to tell when all components initialize, so I agree that should be the main goal of this PR.
Having one event fire per component init seems potentially excessive and is perhaps a separate bridge we should cross if a convincing use case arises?
Also, I'm not sure whether it makes sense to have the "all initialized" event emit from a particular component, since which component emits it could change just based on how an app changes during development. I'm open to thoughts/arguments otherwise here though.
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.
@kfranqueiro When I submitted the issue I was not sure. The discussion in the issue makes it clear it is about having a way to tell when all components initialize, so I changed its name to be more clear.
I guess using the component to trigger the event was suggested by @yeelan0319 to keep it DRY and reuse the emit method.
I also think the PR should resolve the issue, meaning "all initialized" only until other use case arises.
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.
@yshterev I looked at the comments on the issue and discussion here. I think it was slightly different though when we discuss it internally as we thought it would be done at component level.
So as now we understand the landscape of the question better, I think it should be proper to dispatch a custom event directly instead of using emit
method from a single component. Could you update the PR accordingly? Thanks!
return this.root_; | ||
} | ||
|
||
getDefaultFoundation() { |
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.
Why we are adding Foundation method here? It would inherent from MDCComponent so you don't need to reimplement 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.
Some tests don't pass. The error is Error: Subclasses must override getDefaultFoundation to return a properly configured foundation class
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 once we directly implemented emit function, we no longer need the fake
element here to inherit from MDCComponent
. We can safely change it back to what it was and simply adding two new test cases.
mdcAutoInit(root); | ||
|
||
td.verify(handler(td.matchers.isA(Object))); | ||
}); |
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.
Test looks good!
### Events | ||
|
||
#### MDCAutoInit:End | ||
Triggered when initialization of all components is complete. |
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 that's the case, we probably shouldn't rely on component to emit event.
See my comment below
Hey @yshterev, is there anything unclear about the changes requested here? |
@lynnjepsen Sorry for the delay. PR updated. |
What should I do to pass the codecov test? Maybe rebase from 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.
@yshterev Thanks for updating the PR. The codecov failed because line 37/38 in mdc-auto-init.js
is not being covered, thus make the code coverage drop below the requirement. Please take a look at line 157 in test/unit/mdc-base/components.test.js
to see how emit
is tested.
return this.root_; | ||
} | ||
|
||
getDefaultFoundation() { |
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 once we directly implemented emit function, we no longer need the fake
element here to inherit from MDCComponent
. We can safely change it back to what it was and simply adding two new test cases.
@yshterev Any updates to the changes or let me know if you have more questions! |
FakeComponent in test reverted. 2 new tests added for the emit function. |
packages/mdc-auto-init/index.js
Outdated
* @param {!Object} evtData | ||
* @param {boolean=} shouldBubble | ||
*/ | ||
export function emit(element, evtType, evtData, shouldBubble = false) { |
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.
IMHO, I might not consider making emit a private helper function of mdc-auto-init
instead of public. So far, I cannot see a strong argument why this method need to be public.
If testing is your biggest concern, how about cover both branch using the following methods?
The logic behind this is, we don't need explicitly export emit
to test it but we mock the run-time environment (as you did in testing emit
directly) and see if mdcAutoInit
behave uniformly in both case.
test('#emit event from MDCComponent on init complete', () => {
const root = setupTest();
const handler = td.func('init event handler');
let evt = null;
td.when(handler(td.matchers.isA(Object))).thenDo((evt_) => {
evt = evt_;
});
const type = 'MDCAutoInit:End';
document.addEventListener(type, handler);
mdcAutoInit(root);
assert.isOk(evt !== null);
assert.equal(evt.type, type);
});
test('#emit event from MDCComponent on init complete - custom events not supported', () => {
const root = setupTest();
const handler = td.func('init event handler');
let evt = null;
td.when(handler(td.matchers.isA(Object))).thenDo((evt_) => {
evt = evt_;
});
const type = 'MDCAutoInit:End';
document.addEventListener(type, handler);
const {CustomEvent} = window;
window.CustomEvent = undefined;
try {
mdcAutoInit(root);
} finally {
window.CustomEvent = CustomEvent;
}
assert.isOk(evt !== null);
assert.equal(evt.type, type);
});
Let me know if this makes sense or your consideration for making emit
public. Thanks!
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.
Sure. Your proposal is better. I exported emit
just because of the test. Then the coverage did not pass again and I saw I was missing another test.
Do you think I should remove the element
param from the emit function and just use document
? I don't think element
param makes sense anymore because tests always attach the listener to document.
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.
@yshterev Sorry for the tardiness. Yes. I think that is totally a valid suggestion, right now we are only emitting event at document level, which means the element
is not really being used. Feel free to proceed with this idea and let me know when it is ready to review.
@yeelan0319 Updated |
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.
@yshterev Thanks for the update. I am still a bit worried that we make emit a public function. I left some suggestions and see if you could agree with it.
packages/mdc-auto-init/index.js
Outdated
* @param {!Object} evtData | ||
* @param {boolean=} shouldBubble | ||
*/ | ||
export function emit(evtType, evtData, shouldBubble = false) { |
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.
Could we consider making this a private method?
My concern is there might not be a use case where this function will be called by external user (now).
We could do function emit_
to identify this is a private method and remove export
. I also commented about revoke and test below.
What do you think?
packages/mdc-auto-init/index.js
Outdated
@@ -49,6 +70,8 @@ export default function mdcAutoInit(root = document, warn = CONSOLE_WARN) { | |||
configurable: true, | |||
}); | |||
} | |||
|
|||
emit('MDCAutoInit:End', {}); |
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.
_emit('MDCAutoInit:End', {});
instead.
@@ -18,6 +18,7 @@ import bel from 'bel'; | |||
import td from 'testdouble'; | |||
import {assert} from 'chai'; | |||
import mdcAutoInit from '../../../packages/mdc-auto-init'; | |||
import {emit} from '../../../packages/mdc-auto-init'; |
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.
We can proxy over mdcAutoInit
to test private method emit
is called, so we could remove this line.
@@ -95,3 +96,47 @@ test('#register warns when registered key is being overridden', () => { | |||
|
|||
td.verify(warn(contains('(mdc-auto-init) Overriding registration'))); | |||
}); | |||
|
|||
test('#emit dispatches a custom event with supplied data', () => { |
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.
Consider rewording '#emit dispatches a custom event with supplied data' > '#mdcAutoInit dispatches a MDCAutoInit:End event when initialization of all components is complete'
evt = evt_; | ||
}); | ||
|
||
const data = {evtData: true}; |
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 we could remove this line as the event doesn't come with data
|
||
assert.isOk(evt !== null); | ||
assert.equal(evt.type, type); | ||
assert.deepEqual(evt.detail, data); |
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 we remove data above, also here.
assert.deepEqual(evt.detail, data); | ||
}); | ||
|
||
test('#emit dispatches an event with supplied data - custom events not supported', () => { |
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.
Same thing here. Consider rewording '#mdcAutoInit dispatches a MDCAutoInit:End event when initialization of all components is complete - custom events not supported'?
evt = evt_; | ||
}); | ||
|
||
const data = {evtData: true}; |
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.
Here
const {CustomEvent} = window; | ||
window.CustomEvent = undefined; | ||
try { | ||
emit(type, data); |
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.
And here
|
||
assert.isOk(evt !== null); | ||
assert.equal(evt.type, type); | ||
assert.deepEqual(evt.detail, data); |
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.
And here
@yeelan0319 Sorry .. I was sleepy I guess. Updated. |
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 @yshterev for keeping contributing on it, everything looks great 👍
@yeelan0319 My pleasure 👍 |
FIx #954
@yeelan0319 The dialog component is extending
MDCComponent
so it has direct access toemit
method. I am not sure how to access the emit method properly inmdcAutoInit
function. I tried to importMDCComponent
, but I guess it is not good.Also I am not sure what the test should be.
Any help appreciated.