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
Report user-error from 3p iframe #11002
Conversation
examples/ads.amp.html
Outdated
@@ -208,7 +209,8 @@ | |||
type="a9" | |||
data-aax_size="300x250" | |||
data-aax_pubname="test123" | |||
data-aax_src="302"> | |||
data-aax_src="302" |
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.
pls have a separate example page
examples/ads.amp.html
Outdated
<script type="application/json"> | ||
{ | ||
"requests": { | ||
"user-error": "http://localhost:8000/ampadtest" |
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.
include error type and message in the request
3p/ampcontext.js
Outdated
*/ | ||
errorReport() { | ||
this.win_.addEventListener('error', event => { | ||
if (!!event.error) { |
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.
Unnecessary !!
examples/3p.error.amp.html
Outdated
@@ -0,0 +1,1436 @@ | |||
<!doctype html> |
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 is this file?
for a testing example, you can put in analytics-user-error.amp.html
once that PR is merged
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
@zhouyx I will leave the rest to you |
@@ -206,6 +207,11 @@ export class AmpAdXOriginIframeHandler { | |||
this.sendEmbedInfo_(this.baseInstance_.isInViewport()); | |||
})); | |||
|
|||
this.unlisteners_.push(listenFor(this.iframe, 'user-error', |
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.
nit: Use MessageType.USER_ERROR
.
this.unlisteners_.push(listenFor(this.iframe, 'user-error', | ||
data => { | ||
this.userErrorForAnalytics(data['error'], data['message']); | ||
}, true, 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.
opt_includingNestedWindows set to true if a messages from nested frames should also be accepted.
I don't think you want to include messages from nested frames?
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 mean and why so?
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.
* @param {!Error} error | ||
* @param {string} message | ||
*/ | ||
userErrorForAnalytics(error, message) { |
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.
who is calling this function?
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.
in the listenFor('user-error), line 212
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.
should be private function
3p/ampcontext.js
Outdated
if (!!event.error) { | ||
this.client_.sendMessage(MessageType.USER_ERROR, dict({ | ||
'error': event.error, | ||
'message': event.error.message, |
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 event
the ErrorEvent
? if so should it be event.message
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.
I was thinking event.error returns error so I can get message from that error
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 honestly don't know. Can you make sure?
3p/ampcontext.js
Outdated
@@ -104,6 +104,7 @@ export class AbstractAmpContext { | |||
this.client_ = new IframeMessagingClient(win); | |||
this.client_.setHostWindow(this.getHostWindow_()); | |||
this.client_.setSentinel(dev().assertString(this.sentinel)); | |||
this.errorReport(); |
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.
nit: reportError()
?
3p/ampcontext.js
Outdated
report3pError_() { | ||
this.win_.onerror = function(message) { | ||
if (message) { | ||
this.client_.sendMessage(MessageType.USER_ERROR, dict({ |
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 code here won't work. this
changes in function. You can either use () => {}
or bind this
to the function.
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 in general. Few more comments : )
<amp-youtube width="480" height="270" | ||
data-param-autoplay | ||
data-videoid="dQw4w9WgXcQ"> | ||
</amp-youtube> | ||
|
||
<amp-analytics type="googleanalytics"> | ||
<h1>These create 3P error</h1> | ||
<h2>A9 fake 3p error</h2> |
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 would prefer throw fake error in our fake ping ad. But I am ok with using these two, if they return use error.
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.
yeah these return user error. I can add more errors if 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 am ok with this
* @private | ||
*/ | ||
userErrorForAnalytics_(message) { | ||
const e = new Error(); |
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.
Can we check message is a string here. Just want to be safe.
Then do e = new Error(message);
test/functional/test-amp-context.js
Outdated
}; | ||
windowMessageHandler(message); | ||
|
||
window.onerror = function(message, source, lineno, colno, error) { |
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 see we use describe
here, so please do not rewrite window function. This can potentially break other unrelated tests that depend on window.onerror
.
You can mock it in win
, like what we did for addEventListener
.
Also this test here simply fake everything that we want to test. Can we use the try/catch
we have before?
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.
Because for testing onerror, it will need to manually call the handler instead of how we dealt with addEventListener(). cc @cramforce
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 see. I am however still opposing overwriting window.onerror
here, it would super hard to debug later. We can 1) rewrite the test to use describes
or 2) make the onerror function a method and test that method instead.
test/functional/test-amp-context.js
Outdated
expect(message).to.equal('message'); | ||
context.report3pError_(); | ||
expect(windowPostMessageSpy).to.be.called; | ||
expect(windowPostMessageSpy).to.be.calledWith( |
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.
please use .jsonObject
as we agreed.
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 just took a look at the code, postMessage would call to serializeMessage which will JSON.stringify(message). Therefore I think checking the value as string here is expected.
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.
you can use deserializeMessage
before testing. I know the test works fine, but it would be really hard for people to fix, if it fails for any reason.
src/3p-frame-messaging.js
Outdated
@@ -51,6 +51,9 @@ export const MessageType = { | |||
// For amp-analytics' iframe-transport | |||
SEND_IFRAME_TRANSPORT_EVENTS: 'send-iframe-transport-events', | |||
IFRAME_TRANSPORT_EVENTS: 'iframe-transport-events', | |||
|
|||
// For user-error | |||
USER_ERROR: 'user-error', |
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.
Can we rename this to USER_ERROR_IN_IFRAME
? I find that to be more clear. Thanks
this.unlisteners_.push(listenFor(this.iframe, MessageType.USER_ERROR, | ||
data => { | ||
this.userErrorForAnalytics_(data['message']); | ||
}, true, 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.
please see my previous comments. I really don't think we should listen to message from nested iframe here. Also i don't think nested iframe will send us error message.
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 thought when we talked offline you said you'd prefer to send message around instead of error. What's your suggestion to improve this?
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.
Please see. #11002 (comment)
Let me know if there's any question
3p/ampcontext.js
Outdated
this.win_.onerror = message => { | ||
if (message) { | ||
this.client_.sendMessage(MessageType.USER_ERROR_IN_IRAME, dict({ | ||
'message': message, |
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.
Don't you want the stack?
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 I only need the message to be passed through
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.
Curious how can we get the stack 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.
The 4th argument (I think) of onerror
is the Error
object or undefined.
So you can do 'stack': error && error.stack
test/functional/test-amp-context.js
Outdated
throw e; | ||
} catch (err) { | ||
win.onerror = function(message, source, lineno, colno, error) { | ||
expect(error).to.equal(err); |
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.
Does this actually run? How?
@@ -523,6 +529,18 @@ export class AmpAdXOriginIframeHandler { | |||
this.intersectionObserver_.fire(); | |||
} | |||
} | |||
|
|||
/** | |||
* @param {!string} message |
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.
nit: {string}
src/3p-frame-messaging.js
Outdated
@@ -51,6 +51,9 @@ export const MessageType = { | |||
// For amp-analytics' iframe-transport | |||
SEND_IFRAME_TRANSPORT_EVENTS: 'send-iframe-transport-events', | |||
IFRAME_TRANSPORT_EVENTS: 'iframe-transport-events', | |||
|
|||
// For user-error | |||
USER_ERROR_IN_IRAME: 'user-error', |
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.
nit : USER_ERROR_IN_IFRAME: 'user-error-in-iframe',
3p/ampcontext.js
Outdated
'message': message, | ||
})); | ||
} | ||
return 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.
just curious, do we have to return false
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.
if we don't return false then it would be undefined, which is false. But i think we should explicitly return false to make it readable
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
3p/ampcontext.js
Outdated
this.win_.onerror = message => { | ||
if (message) { | ||
this.client_.sendMessage(MessageType.USER_ERROR_IN_IRAME, dict({ | ||
'message': message, |
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.
Curious how can we get the stack here?
3p/ampcontext.js
Outdated
'message': message, | ||
})); | ||
} | ||
return 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.
sounds good
<amp-youtube width="480" height="270" | ||
data-param-autoplay | ||
data-videoid="dQw4w9WgXcQ"> | ||
</amp-youtube> | ||
|
||
<amp-analytics type="googleanalytics"> | ||
<h1>These create 3P error</h1> | ||
<h2>A9 fake 3p error</h2> |
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 ok with this
src/3p-frame-messaging.js
Outdated
@@ -51,6 +51,9 @@ export const MessageType = { | |||
// For amp-analytics' iframe-transport | |||
SEND_IFRAME_TRANSPORT_EVENTS: 'send-iframe-transport-events', | |||
IFRAME_TRANSPORT_EVENTS: 'iframe-transport-events', | |||
|
|||
// For user-error-in-iframe | |||
USER_ERROR_IN_IRAME: 'user-error-in-iframe', |
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.
nit: USER_ERROR_IN_IFRAME
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.
LGTM
test/functional/test-amp-context.js
Outdated
@@ -32,8 +32,6 @@ describe('3p ampcontext.js', () => { | |||
windowPostMessageSpy = sandbox.spy(); | |||
win = { | |||
addEventListener: (eventType, handlerFn) => { | |||
expect(eventType).to.equal('message'); |
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.
don't think you should remove Alan's test here though.
test/functional/test-amp-context.js
Outdated
win.name = generateSerializedAttributes(); | ||
const context = new AmpContext(win); | ||
expect(context).to.be.ok; | ||
context.report3pError_(); |
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 question again, the constructor already called report3pError_()
why we need to call it 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.
i needed it to test addEventListener call before, but forgot to remove. Will change now.
test/functional/test-amp-context.js
Outdated
@@ -61,6 +59,24 @@ describe('3p ampcontext.js', () => { | |||
windowMessageHandler = undefined; | |||
}); | |||
|
|||
it('should send message when report3pError_()', () => { |
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.
nit: 'should send error message with report3pError_'
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.
LGTM
See comments about stack traces (if appliacable).
For #10892