Skip to content
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

type(feat): Implemented Notification Classes #322

Merged
merged 4 commits into from
Dec 16, 2024

Conversation

Temidayo32
Copy link
Collaborator

Because

  • AddOnInstallFailed, AddOnProgress, and AddOnInstallRestart classes are not implemented yet.

This commit

  • Implemented the AddOnInstallFailed, AddOnProgress, and AddOnInstallRestart classes

Fixes #311

@Temidayo32 Temidayo32 changed the title Notification type(feat): Implemented Notification Classes Oct 23, 2024
@Temidayo32
Copy link
Collaborator Author

Hi @b4handjr I haven't written the tests for the classes yet. I just want to run the implementation I have here by you to know if there are any adjustments before I proceed with writing the tests. I would appreciate you looking over it. Thanks.

@b4handjr
Copy link
Contributor

This looks like a fine start, I am waiting a bit to merge a fix for the tests as I am hoping there are some more attempts at it. You could probably work on tests but you might not be able to push the code for a little while.

@Temidayo32
Copy link
Collaborator Author

Temidayo32 commented Oct 24, 2024

This looks like a fine start, I am waiting a bit to merge a fix for the tests as I am hoping there are some more attempts at it. You could probably work on tests but you might not be able to push the code for a little while.

Oh, okay. Thanks for looking through this I will proceed with writing the tests.

@Temidayo32
Copy link
Collaborator Author

Temidayo32 commented Oct 27, 2024

@b4handjr While I written the test for AddOnInstallFailed, I haven't been able to add test for the other two. For AddOnInstallRestart, it appears to me that Firefox has fully transitioned to restartless addons and the notification for restart is no longer displayed.

On the other for AddOnInstallProgress, I wasn't able to capture the notification even though the notification popup does appear as shown.

1730048847859_progress

On investigation, I discovered geckodriver isn't capturing the logs for the progress element. I pasted the driver logs here: https://paste.mozilla.org/f2FMCbpc

Here is the most important part. The addon-progress-notification element is not captures here at all.

1730047021342	Marionette	TRACE	[11] Received event DOMContentLoaded for http://127.0.0.1:37233/
1730047021342	Marionette	TRACE	[11] Received event pageshow for http://127.0.0.1:37233/
1730047021342	Marionette	DEBUG	0 <- [1,3,null,{"value":null}]
1730047021348	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047021349	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element {"using": "link text", "value": "largewebextension.xpi"}
1730047021351	Marionette	DEBUG	0 -> [0,4,"WebDriver:FindElement",{"using":"link text","value":"largewebextension.xpi"}]
1730047021353	RemoteAgent	TRACE	WebDriverProcessData actor created for PID 1180094
1730047021353	Marionette	TRACE	[11] MarionetteCommands actor created for window id 10737418241
1730047021365	Marionette	DEBUG	0 <- [1,4,null,{"value":{"element-6066-11e4-a52e-4f735466cecf":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}}]
1730047021365	webdriver::server	DEBUG	<- 200 OK {"value":{"element-6066-11e4-a52e-4f735466cecf":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}}
1730047021366	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element/8b07f1d7-50a4-4def-9418-d4f6a9c692fa/click {}
1730047021367	Marionette	DEBUG	0 -> [0,5,"WebDriver:ElementClick",{"id":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}]
1730047021379	Marionette	TRACE	Received DOM event click for http://127.0.0.1:37233/largewebextension.xpi
1730047021383	Marionette	TRACE	[11] Received event beforeunload for http://127.0.0.1:37233/
1730047028355	Marionette	TRACE	Canceled page load listener because no navigation has been detected
1730047028356	Marionette	DEBUG	0 <- [1,5,null,{"value":null}]
1730047028356	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047028358	webdriver::server	DEBUG	-> GET /session/7f28824c-61cf-483d-b24c-df67c05c7c10/moz/context 
1730047028358	Marionette	DEBUG	0 -> [0,6,"Marionette:GetContext",{}]
1730047028359	Marionette	DEBUG	0 <- [1,6,null,{"value":"content"}]
1730047028359	webdriver::server	DEBUG	<- 200 OK {"value":"content"}
1730047028360	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/moz/context {"context": "chrome"}
1730047028361	Marionette	DEBUG	0 -> [0,7,"Marionette:SetContext",{"value":"chrome"}]
1730047028361	Marionette	DEBUG	0 <- [1,7,null,{"value":null}]
1730047028361	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047028362	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element {"using": "css selector", "value": "#notification-popup popupnotification"}
1730047028362	Marionette	DEBUG	0 -> [0,8,"WebDriver:FindElement",{"using":"css selector","value":"#notification-popup popupnotification"}]
1730047028364	RemoteAgent	TRACE	WebDriverProcessData actor created for PID 1179885
1730047028364	Marionette	TRACE	[1] MarionetteCommands actor created for window id 2
1730047028365	Marionette	DEBUG	0 <- [1,8,null,{"value":{"element-6066-11e4-a52e-4f735466cecf":"f489ac48-6eb8-47f8-8b94-2aa970a366c8"}}]
1730047028365	webdriver::server	DEBUG	<- 200 OK {"value":{"element-6066-11e4-a52e-4f735466cecf":"f489ac48-6eb8-47f8-8b94-2aa970a366c8"}}
1730047028366	webdriver::server	DEBUG	-> GET /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element/f489ac48-6eb8-47f8-8b94-2aa970a366c8/property/id 
1730047028367	Marionette	DEBUG	0 -> [0,9,"WebDriver:GetElementProperty",{"id":"f489ac48-6eb8-47f8-8b94-2aa970a366c8","name":"id"}]
1730047028367	Marionette	DEBUG	0 <- [1,9,null,{"value":"addon-install-failed-notification"}]
1730047028367	webdriver::server	DEBUG	<- 200 OK {"value":"addon-install-failed-notification"}

@Temidayo32
Copy link
Collaborator Author

@b4handjr While I written the test for AddOnInstallFailed, I haven't been able to add test for the other two. For AddOnInstallRestart, it appears to me that Firefox has fully transitioned to restartless addons and the notification for restart is no longer displayed.

On the other for AddOnInstallProgress, I wasn't able to capture the notification even though the notification popup does appear as shown.

1730048847859_progress 1730048847859_progress

On investigation, I discovered geckodriver isn't capturing the logs for the progress element. I pasted the driver logs here: https://paste.mozilla.org/f2FMCbpc

Here is the most important part. The addon-progress-notification element is not captures here at all.

1730047021342	Marionette	TRACE	[11] Received event DOMContentLoaded for http://127.0.0.1:37233/
1730047021342	Marionette	TRACE	[11] Received event pageshow for http://127.0.0.1:37233/
1730047021342	Marionette	DEBUG	0 <- [1,3,null,{"value":null}]
1730047021348	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047021349	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element {"using": "link text", "value": "largewebextension.xpi"}
1730047021351	Marionette	DEBUG	0 -> [0,4,"WebDriver:FindElement",{"using":"link text","value":"largewebextension.xpi"}]
1730047021353	RemoteAgent	TRACE	WebDriverProcessData actor created for PID 1180094
1730047021353	Marionette	TRACE	[11] MarionetteCommands actor created for window id 10737418241
1730047021365	Marionette	DEBUG	0 <- [1,4,null,{"value":{"element-6066-11e4-a52e-4f735466cecf":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}}]
1730047021365	webdriver::server	DEBUG	<- 200 OK {"value":{"element-6066-11e4-a52e-4f735466cecf":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}}
1730047021366	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element/8b07f1d7-50a4-4def-9418-d4f6a9c692fa/click {}
1730047021367	Marionette	DEBUG	0 -> [0,5,"WebDriver:ElementClick",{"id":"8b07f1d7-50a4-4def-9418-d4f6a9c692fa"}]
1730047021379	Marionette	TRACE	Received DOM event click for http://127.0.0.1:37233/largewebextension.xpi
1730047021383	Marionette	TRACE	[11] Received event beforeunload for http://127.0.0.1:37233/
1730047028355	Marionette	TRACE	Canceled page load listener because no navigation has been detected
1730047028356	Marionette	DEBUG	0 <- [1,5,null,{"value":null}]
1730047028356	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047028358	webdriver::server	DEBUG	-> GET /session/7f28824c-61cf-483d-b24c-df67c05c7c10/moz/context 
1730047028358	Marionette	DEBUG	0 -> [0,6,"Marionette:GetContext",{}]
1730047028359	Marionette	DEBUG	0 <- [1,6,null,{"value":"content"}]
1730047028359	webdriver::server	DEBUG	<- 200 OK {"value":"content"}
1730047028360	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/moz/context {"context": "chrome"}
1730047028361	Marionette	DEBUG	0 -> [0,7,"Marionette:SetContext",{"value":"chrome"}]
1730047028361	Marionette	DEBUG	0 <- [1,7,null,{"value":null}]
1730047028361	webdriver::server	DEBUG	<- 200 OK {"value":null}
1730047028362	webdriver::server	DEBUG	-> POST /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element {"using": "css selector", "value": "#notification-popup popupnotification"}
1730047028362	Marionette	DEBUG	0 -> [0,8,"WebDriver:FindElement",{"using":"css selector","value":"#notification-popup popupnotification"}]
1730047028364	RemoteAgent	TRACE	WebDriverProcessData actor created for PID 1179885
1730047028364	Marionette	TRACE	[1] MarionetteCommands actor created for window id 2
1730047028365	Marionette	DEBUG	0 <- [1,8,null,{"value":{"element-6066-11e4-a52e-4f735466cecf":"f489ac48-6eb8-47f8-8b94-2aa970a366c8"}}]
1730047028365	webdriver::server	DEBUG	<- 200 OK {"value":{"element-6066-11e4-a52e-4f735466cecf":"f489ac48-6eb8-47f8-8b94-2aa970a366c8"}}
1730047028366	webdriver::server	DEBUG	-> GET /session/7f28824c-61cf-483d-b24c-df67c05c7c10/element/f489ac48-6eb8-47f8-8b94-2aa970a366c8/property/id 
1730047028367	Marionette	DEBUG	0 -> [0,9,"WebDriver:GetElementProperty",{"id":"f489ac48-6eb8-47f8-8b94-2aa970a366c8","name":"id"}]
1730047028367	Marionette	DEBUG	0 <- [1,9,null,{"value":"addon-install-failed-notification"}]
1730047028367	webdriver::server	DEBUG	<- 200 OK {"value":"addon-install-failed-notification"}

As a follow up on this, I asked in the Webdriver channel, and I got to learn that there is a bit of time when the main thread is blocked while installing the addon, which could be a plausible reason.

@Temidayo32 Temidayo32 force-pushed the notification branch 3 times, most recently from 9dcb409 to 7d031a8 Compare November 1, 2024 12:36
Copy link
Contributor

@b4handjr b4handjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had some initial thoughts but it seems you're still working on tests.

Comment on lines 48 to 50
def get_path(self, size="default"):
"""Returns web extension path."""
return self.paths.get(size, self.paths["default"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is size here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be a property so we can use setters and getters on it.

Returns:
:py:class:`AddOnInstallFailed`: Firefox notification.
"""
selenium.get(webserver.url())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated but we should change url to just be a property.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will work on this

Comment on lines +96 to +90
def is_downloading(self):
"""Check if the add-on is currently downloading.

Returns:
bool: True if the download and verification is in progress.
"""
with self.selenium.context(self.selenium.CONTEXT_CHROME):
return "Downloading and verifying add-on…" in self.find_description().text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what's the idea with this. I can see some use cases but I would like to know you're thinking. How would the API look for a user who wants to use this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this as property here because I think this is a good identifier of the Firefox Progress notification. The idea is for the property to return a boolean. A simple true or false could be used to easily determine if the Progress notification is active or not. In the context of the test for notification, if progress_notification returns the AddOnProgress class, then the API will be progress_notification.is_downloading.

Comment on lines 105 to 111
def wait_until_complete(self, timeout=None):
"""Wait until the progress notification disappears, indicating completion.

Args:
timeout (int, optional): Maximum time to wait in seconds.
"""
self.window.wait_for_notification(None, timeout=timeout)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this return something when it has been completed? Even returning the self.window.wait_for_notification(None, timeout=timeout) seems fine, as that returns the notification itself.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing that out. I think this could be potentially confusing if there is no return. Actually, from what I have observed of the Firefox notification for progress, the notification disappears once the download is completed. So I think it will be more accurate to return a boolean that shows that the notification is no longer active or visible.

 return self.window.wait_for_notification(None, timeout=timeout) is None
 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I notice that your call to wait_for_notification uses None, I think we would want to wait for this AddOnProgress notification right? I know that you can wait for any notification with that method, but it wouldn't seems right to have that be within this class. So do we need this method at all? When a download is completed there should be only a few different results from that, it seems to make sense to check for those. I think if you write a test for this it will help clarify what you had in mind.

Copy link
Collaborator Author

@Temidayo32 Temidayo32 Nov 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, when a download completes, no result is usually displayed that shows the download has completed. When a download completes, the notification will no longer be visible. Usually, it is followed by the Add-on install complete notification or Blocked notification if it is potentially, a suspicious extension.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so we could wait for one of those, since we know they will be shown after it is completed.

@b4handjr b4handjr self-requested a review November 12, 2024 20:30
@Temidayo32
Copy link
Collaborator Author

@b4handjr Here is a feedback on the report I made as regards the AddOnProgress notification not appearing and the difficulty capturing it. So I reported it to the WebDriver channel, and I have been given the go-ahead to modify one of Marionette files, specifically, a time delay variable, and hopefully, this should resolve the issue.

@Temidayo32
Copy link
Collaborator Author

Follow up: As suspected, a time delay variable with respect to an event that occurs during a page load, unload event, is at the root cause of the inability to capture the AddOnProgress notification. A bug has been filed for it here:

https://bugzilla.mozilla.org/show_bug.cgi?id=1931297

I will be sending in a patch.

@b4handjr
Copy link
Contributor

Follow up: As suspected, a time delay variable with respect to an event that occurs during a page load, unload event, is at the root cause of the inability to capture the AddOnProgress notification. A bug has been filed for it here:

https://bugzilla.mozilla.org/show_bug.cgi?id=1931297

I will be sending in a patch.

Very nice, glad we could find that bug. Great work!

@Temidayo32
Copy link
Collaborator Author

Follow up: As suspected, a time delay variable with respect to an event that occurs during a page load, unload event, is at the root cause of the inability to capture the AddOnProgress notification. A bug has been filed for it here:
https://bugzilla.mozilla.org/show_bug.cgi?id=1931297
I will be sending in a patch.

Very nice, glad we could find that bug. Great work!

Yeah!

@Temidayo32
Copy link
Collaborator Author

Temidayo32 commented Nov 16, 2024

Update: This is the fix that was made. It wasn't ideal to completely remove the timer variable that had blocked the capture of the progress notification. It served a key purpose during navigation events (beforeunload and unload events), so it can't be removed. However, a work around was implemented. This fix is when the pageLoadStrategy is None (implying there is no actually navigation), the timer will not be applied. This small logic has been added on the Firefox side in the bug I shared above. The implication is that when writing the test to capture the progress notification, I added the extra configuration that sets pageLoadStrategy to None, which would then skip the timer. An extra implication is that skipping the timer means I have to manually add a WebDriverWait in the fixture for progress_notification that waits until the page containing the extension is fully loaded before sending the click event.

I have now made a commit for progress_notification. To also ensure we are able to capture the progress_notification, I added a new web extension xpi that won't trigger the blocked notification.

@Temidayo32
Copy link
Collaborator Author

Also, I think I can remove the test class for AddonRestart as it is now deprecated. Yes?

Comment on lines 54 to 61
@property
def path(self):
"""Default path."""
return self._paths["default"]

def get_path(self, ext_path):
"""Returns the web extension path."""
return self._paths.get(ext_path)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like where this is going but it is not the proper use of a property. get_path shouldn't need to exist, as we should be able to set a path and return it from the property itself. Here is a good article on what I mean, https://realpython.com/python-getter-setter/#using-properties-instead-of-getters-and-setters-the-python-way

@b4handjr
Copy link
Contributor

Also, I think I can remove the test class for AddonRestart as it is now deprecated. Yes?

Yes, that sounds good

@Temidayo32 Temidayo32 force-pushed the notification branch 4 times, most recently from 0f0c70a to d089330 Compare November 16, 2024 18:36
@Temidayo32
Copy link
Collaborator Author

@b4handjr I have made the requested changes.

Copy link
Contributor

@b4handjr b4handjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making good progress here!

Comment on lines +44 to +51
self._paths = {
"default": "webextension.xpi",
"corrupt": "corruptwebextension.xpi",
"large": "largewebextension.xpi",
}
if path_key not in self._paths:
raise ValueError(f"Invalid path key: {path_key}")
self._path_key = path_key
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the paths dict here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines +73 to +77
def close(self):
"""Close the failed installation notification."""
with self.selenium.context(self.selenium.CONTEXT_CHROME):
self.find_primary_button().click()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this to the Failed test?

Comment on lines +63 to +64
else:
raise ValueError(f"Invalid path key: {ext_path}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a test for this error case?

Comment on lines 135 to 137
def failed_notification(
addon: AddOn, browser: BrowserWindow, webserver: WebServer, selenium: WebDriver
):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't have a return type

Comment on lines 75 to 76
addon: AddOn, browser: BrowserWindow, webserver: WebServer, selenium: WebDriver
) -> BaseNotification:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this not return AddOnProgress?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can. I have addressed it.

Comment on lines 150 to 151
browser: BrowserWindow, blocked_notification: AddOnInstallBlocked
) -> BaseNotification | None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix this to just return None since it is a test.

Comment on lines +239 to +253
@pytest.mark.parametrize(
"firefox_options", [{"page_load_strategy_none": True}], indirect=True
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of parrametrization!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Temidayo32
Copy link
Collaborator Author

Temidayo32 commented Nov 20, 2024

@b4handjr I have made the requested changes. Thanks for pointing out the issues.

(Also, I left a message for you in the Desktop Test Engineering in Mozilla Chat. It is an inquiry and I will be grateful if you can look into it. thanks).

@Temidayo32
Copy link
Collaborator Author

@b4handjr Can this merged yet or there are still more changes I need to make? Thanks.

@b4handjr b4handjr self-requested a review November 25, 2024 16:12
@b4handjr
Copy link
Contributor

It's a busy week here at Mozilla, I will try and get to it this week though.

Copy link
Contributor

@b4handjr b4handjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had 1 more question

) -> None:
"""Verify downloading status is reported correctly."""
description = progress_notification.is_downloading
assert description is not None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_downloading is said to be type bool. Is it hard to check if it's true or has been set to true?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@b4handjr Oh, not at all. Let me change it to assert description is True to clarify it.

Copy link
Contributor

@b4handjr b4handjr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, thanks for this!

@b4handjr
Copy link
Contributor

The Nightly tests are failing due to the browser-actions plugin, browser-actions/setup-firefox#621

@b4handjr b4handjr merged commit 5b208d1 into mozilla:main Dec 16, 2024
6 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update addons notification features
2 participants