# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, you can obtain one at http://mozilla.org/MPL/2.0/. import json import os.path from marionette_harness import MarionetteTestCase here = os.path.dirname(__file__) COMPOSE_WINDOW = "chrome://messenger/content/messengercompose/messengercompose.xhtml" MESSENGER_WINDOW = "chrome://messenger/content/messenger.xhtml" MESSAGE_WINDOW = "chrome://messenger/content/messageWindow.xhtml" # Account prefs, so that a compose window can be opened. COMPOSE_PREFS = { "mail.account.account1.identities": "id1", "mail.account.account1.server": "server1", "mail.accountmanager.accounts": "account1", "mail.accountmanager.defaultaccount": "account1", "mail.identity.id1.fullName": "Marionette", "mail.identity.id1.useremail": "marionette@invalid", "mail.identity.id1.valid": True, "mail.server.server1.hostname": "localhost", "mail.server.server1.login_at_startup": False, "mail.server.server1.type": "pop3", } class TestCollapsedToolbarMigration(MarionetteTestCase): """ Tests that the legacy collapsed="true"/"false" values, as written by Thunderbird 9 to 60, are rewritten to the values the current code persists, since the presence of *any* value for that attribute now collapses the toolbar. """ # The toolbars are near the end of messengercompose.xhtml, so wait for the # compose window to be ready before looking for them. get_collapsed_attributes = """ const [resolve] = arguments; function finish() { resolve([ document.getElementById("composeToolbar2").getAttribute("collapsed"), document.getElementById("compose-toolbar-menubar2").getAttribute("collapsed"), ]); } if (window.composeEditorReady) { finish(); } else { window.addEventListener("compose-editor-ready", finish, { once: true }); } """ get_xulstore_value = """ const [url, id] = arguments; if (!Services.xulStore.hasValue(url, id, "collapsed")) { return null; } return Services.xulStore.getValue(url, id, "collapsed"); """ get_pref_value = """ return Services.prefs.getIntPref("mail.ui-rdf.version", -1); """ def test_no_xulstore_update(self): """ The XUL store has no value when migration happens. Nothing is written and the toolbars should be visible, because that's the default. """ self.subtest(61, None, [None, None], None) def test_xulstore_false_no_update(self): """ The XUL store value is false and migration doesn't happen. The toolbars should be collapsed, because they have a value for the collapsed attribute, even though that value is "false". """ self.subtest(62, "false", ["false", "false"], "false") def test_xulstore_false_update(self): """ The XUL store value is false when migration happens. It should become "-moz-missing\n" and the toolbars should be visible. """ self.subtest(61, "false", [None, None], "-moz-missing\n") def test_xulstore_true_update(self): """ The XUL store value is true when migration happens. It should be normalized to "" and the toolbars should stay collapsed. """ self.subtest(61, "true", ["", ""], "") def test_xulstore_missing_update(self): """ The XUL store value is already "-moz-missing\n", as written by the current code for a visible toolbar, or by a user working around this bug by toggling the setting. It must be left alone, so the toolbars stay visible. """ self.subtest(61, "-moz-missing\n", [None, None], "-moz-missing\n") def test_xulstore_empty_update(self): """ The XUL store value is already "", as written by the current code for a collapsed toolbar. It must be left alone, so the toolbars stay collapsed. """ self.subtest(61, "", ["", ""], "") def subtest( self, migration_version, xulstore_value, expected_attribute_values, expected_xulstore_value, ): self.marionette.set_context(self.marionette.CONTEXT_CHROME) self.marionette.set_prefs(COMPOSE_PREFS) self.marionette.quit(in_app=True) # Set the migration pref to a number lower than the migration we're # testing, without clobbering the account prefs written on shutdown. prefs_path = os.path.join(self.marionette.profile_path, "prefs.js") with open(prefs_path, "a") as prefs_file: prefs_file.write(f"""user_pref("mail.ui-rdf.version", {migration_version});\n""") # Write a xulstore.json file with the collapsed attribute set. xulstore_path = os.path.join(self.marionette.profile_path, "xulstore.json") if xulstore_value is None: xulstore_data = {COMPOSE_WINDOW: {}} else: xulstore_data = { COMPOSE_WINDOW: { "composeToolbar2": {"collapsed": xulstore_value}, "compose-toolbar-menubar2": {"collapsed": xulstore_value}, }, MESSENGER_WINDOW: {"mail-bar3": {"collapsed": xulstore_value}}, MESSAGE_WINDOW: {"mail-bar3": {"collapsed": xulstore_value}}, } with open(xulstore_path, "w") as xulstore_file: json.dump(xulstore_data, xulstore_file) # Start the application with a compose window, check the state. self.marionette.instance.app_args = ["mailto:test@invalid"] try: self.marionette.start_session() self.marionette.set_context(self.marionette.CONTEXT_CHROME) for url, id in ( (COMPOSE_WINDOW, "composeToolbar2"), (COMPOSE_WINDOW, "compose-toolbar-menubar2"), (MESSENGER_WINDOW, "mail-bar3"), (MESSAGE_WINDOW, "mail-bar3"), ): self.assertEqual( expected_xulstore_value, self.marionette.execute_script(self.get_xulstore_value, [url, id]), f"XUL store value for {id} in {url}", ) self.assertTrue(self.marionette.execute_script(self.get_pref_value) >= 62) handles = self.marionette.chrome_window_handles self.assertEqual(2, len(handles)) self.marionette.switch_to_window(handles[1], True) self.assertEqual("msgcompose", self.marionette.get_window_type()) self.assertEqual( expected_attribute_values, self.marionette.execute_async_script(self.get_collapsed_attributes), ) finally: for key in COMPOSE_PREFS: self.marionette.clear_pref(key) self.marionette.instance.app_args = [] self.marionette.quit(in_app=True)