From 67982ac133ab0ff62122b7f246c9b82b4932876b Mon Sep 17 00:00:00 2001
From: Micah Lee <micah@micahflee.com>
Date: Fri, 4 Jan 2019 15:17:34 -0800
Subject: [PATCH 1/5] Add python3 to Build-Depends

---
 stdeb.cfg | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/stdeb.cfg b/stdeb.cfg
index f32730fa..de6c52c2 100644
--- a/stdeb.cfg
+++ b/stdeb.cfg
@@ -1,6 +1,6 @@
 [DEFAULT]
 Package3: onionshare
-Depends3: python3-flask, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python-nautilus, tor, obfs4proxy
-Build-Depends: python3-pytest, python3-flask, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python-nautilus, tor, obfs4proxy
+Depends3: python3, python3-flask, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python-nautilus, tor, obfs4proxy
+Build-Depends: python3, python3-pytest, python3-flask, python3-stem, python3-pyqt5, python3-crypto, python3-socks, python3-distutils, python-nautilus, tor, obfs4proxy
 Suite: bionic
 X-Python3-Version: >= 3.5.3

From ecc9ef705a2a87b0ff16ccde036f9e5a7d2e4e6a Mon Sep 17 00:00:00 2001
From: Micah Lee <micah@micahflee.com>
Date: Tue, 15 Jan 2019 21:52:42 -0800
Subject: [PATCH 2/5] Make it so GUI tests only run with --rungui

---
 tests/conftest.py                             | 21 +++++++++++++------
 ...re_404_public_mode_skips_ratelimit_test.py |  2 ++
 ..._onionshare_404_triggers_ratelimit_test.py |  2 ++
 ...tting_during_share_prompts_warning_test.py |  2 ++
 ...onshare_receive_mode_sender_closed_test.py |  2 ++
 ...ocal_onionshare_receive_mode_timer_test.py |  2 ++
 ...ceive_mode_upload_non_writable_dir_test.py |  2 ++
 ...pload_public_mode_non_writable_dir_test.py |  2 ++
 ...re_receive_mode_upload_public_mode_test.py |  2 ++
 ...cal_onionshare_receive_mode_upload_test.py |  2 ++
 ...onshare_settings_dialog_legacy_tor_test.py |  2 ++
 ..._onionshare_settings_dialog_no_tor_test.py |  2 ++
 ..._onionshare_settings_dialog_v3_tor_test.py |  2 ++
 ...re_share_mode_download_public_mode_test.py |  2 ++
 ...hare_share_mode_download_stay_open_test.py |  2 ++
 ...cal_onionshare_share_mode_download_test.py |  2 ++
 ...ionshare_share_mode_large_download_test.py |  2 ++
 ...onshare_share_mode_slug_persistent_test.py |  2 ++
 .../local_onionshare_share_mode_timer_test.py |  2 ++
 ...onshare_share_mode_timer_too_short_test.py |  2 ++
 ...onshare_share_mode_unreadable_file_test.py |  2 ++
 ...onshare_790_cancel_on_second_share_test.py |  3 ++-
 ...re_receive_mode_upload_public_mode_test.py |  1 +
 tests/onionshare_receive_mode_upload_test.py  |  1 +
 ...onionshare_share_mode_cancel_share_test.py |  1 +
 ...re_share_mode_download_public_mode_test.py |  1 +
 ...hare_share_mode_download_stay_open_test.py |  1 +
 tests/onionshare_share_mode_download_test.py  |  1 +
 .../onionshare_share_mode_persistent_test.py  |  1 +
 tests/onionshare_share_mode_stealth_test.py   |  1 +
 tests/onionshare_share_mode_timer_test.py     |  1 +
 ...e_share_mode_tor_connection_killed_test.py |  1 +
 tests/onionshare_share_mode_v2_onion_test.py  |  1 +
 33 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/tests/conftest.py b/tests/conftest.py
index 688b22d8..7aca2b2c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -11,19 +11,28 @@ import pytest
 from onionshare import common, web, settings, strings
 
 def pytest_addoption(parser):
+    parser.addoption(
+        "--rungui", action="store_true", default=False, help="run GUI tests"
+    )
     parser.addoption(
         "--runtor", action="store_true", default=False, help="run tor tests"
     )
 
 
 def pytest_collection_modifyitems(config, items):
-    if config.getoption("--runtor"):
+    if not config.getoption("--runtor"):
         # --runtor given in cli: do not skip tor tests
-        return
-    skip_tor = pytest.mark.skip(reason="need --runtor option to run")
-    for item in items:
-        if "tor" in item.keywords:
-            item.add_marker(skip_tor)
+        skip_tor = pytest.mark.skip(reason="need --runtor option to run")
+        for item in items:
+            if "tor" in item.keywords:
+                item.add_marker(skip_tor)
+
+    if not config.getoption('--rungui'):
+        # --rungui given in cli: do not skip GUI tests
+        skip_gui = pytest.mark.skip(reason="need --rungui option to run")
+        for item in items:
+            if "gui" in item.keywords:
+                item.add_marker(skip_gui)
 
 
 @pytest.fixture
diff --git a/tests/local_onionshare_404_public_mode_skips_ratelimit_test.py b/tests/local_onionshare_404_public_mode_skips_ratelimit_test.py
index 11feb6f0..ebb524c2 100644
--- a/tests/local_onionshare_404_public_mode_skips_ratelimit_test.py
+++ b/tests/local_onionshare_404_public_mode_skips_ratelimit_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -16,6 +17,7 @@ class Local404PublicModeRateLimitTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(True, True)
diff --git a/tests/local_onionshare_404_triggers_ratelimit_test.py b/tests/local_onionshare_404_triggers_ratelimit_test.py
index ad49c3f8..8ed0777a 100644
--- a/tests/local_onionshare_404_triggers_ratelimit_test.py
+++ b/tests/local_onionshare_404_triggers_ratelimit_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -15,6 +16,7 @@ class Local404RateLimitTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(False, True)
diff --git a/tests/local_onionshare_quitting_during_share_prompts_warning_test.py b/tests/local_onionshare_quitting_during_share_prompts_warning_test.py
index d2fe4986..e57167c8 100644
--- a/tests/local_onionshare_quitting_during_share_prompts_warning_test.py
+++ b/tests/local_onionshare_quitting_during_share_prompts_warning_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 from PyQt5 import QtCore, QtTest
 
@@ -16,6 +17,7 @@ class LocalQuittingDuringSharePromptsWarningTest(unittest.TestCase, GuiShareTest
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(False, True)
diff --git a/tests/local_onionshare_receive_mode_sender_closed_test.py b/tests/local_onionshare_receive_mode_sender_closed_test.py
index e177d2ef..bfb9499a 100644
--- a/tests/local_onionshare_receive_mode_sender_closed_test.py
+++ b/tests/local_onionshare_receive_mode_sender_closed_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -15,6 +16,7 @@ class LocalReceiveModeSenderClosedTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_tests(False, True)
diff --git a/tests/local_onionshare_receive_mode_timer_test.py b/tests/local_onionshare_receive_mode_timer_test.py
index 88002f94..0acaa4a9 100644
--- a/tests/local_onionshare_receive_mode_timer_test.py
+++ b/tests/local_onionshare_receive_mode_timer_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -16,6 +17,7 @@ class LocalReceiveModeTimerTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_timer_tests(False)
diff --git a/tests/local_onionshare_receive_mode_upload_non_writable_dir_test.py b/tests/local_onionshare_receive_mode_upload_non_writable_dir_test.py
index 7d7b2780..a1dcd679 100644
--- a/tests/local_onionshare_receive_mode_upload_non_writable_dir_test.py
+++ b/tests/local_onionshare_receive_mode_upload_non_writable_dir_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -15,6 +16,7 @@ class LocalReceiveModeUnwritableTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_unwritable_dir_tests(False, True)
diff --git a/tests/local_onionshare_receive_mode_upload_public_mode_non_writable_dir_test.py b/tests/local_onionshare_receive_mode_upload_public_mode_non_writable_dir_test.py
index cdc4e62a..529e0c87 100644
--- a/tests/local_onionshare_receive_mode_upload_public_mode_non_writable_dir_test.py
+++ b/tests/local_onionshare_receive_mode_upload_public_mode_non_writable_dir_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -16,6 +17,7 @@ class LocalReceivePublicModeUnwritableTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_unwritable_dir_tests(True, True)
diff --git a/tests/local_onionshare_receive_mode_upload_public_mode_test.py b/tests/local_onionshare_receive_mode_upload_public_mode_test.py
index bedb7ae2..f8bd38bd 100644
--- a/tests/local_onionshare_receive_mode_upload_public_mode_test.py
+++ b/tests/local_onionshare_receive_mode_upload_public_mode_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -16,6 +17,7 @@ class LocalReceiveModePublicModeTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_tests(True, True)
diff --git a/tests/local_onionshare_receive_mode_upload_test.py b/tests/local_onionshare_receive_mode_upload_test.py
index 82baf3fd..362e3b85 100644
--- a/tests/local_onionshare_receive_mode_upload_test.py
+++ b/tests/local_onionshare_receive_mode_upload_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiReceiveTest import GuiReceiveTest
@@ -15,6 +16,7 @@ class LocalReceiveModeTest(unittest.TestCase, GuiReceiveTest):
     def tearDownClass(cls):
         GuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_receive_mode_tests(False, True)
diff --git a/tests/local_onionshare_settings_dialog_legacy_tor_test.py b/tests/local_onionshare_settings_dialog_legacy_tor_test.py
index ae6ce272..f32023fe 100644
--- a/tests/local_onionshare_settings_dialog_legacy_tor_test.py
+++ b/tests/local_onionshare_settings_dialog_legacy_tor_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from onionshare import strings
@@ -14,6 +15,7 @@ class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
     def tearDownClass(cls):
         SettingsGuiBaseTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui_legacy_tor(self):
         self.gui.onion = OnionStub(True, False)
         self.gui.reload_settings()
diff --git a/tests/local_onionshare_settings_dialog_no_tor_test.py b/tests/local_onionshare_settings_dialog_no_tor_test.py
index f01e049d..b34cbff3 100644
--- a/tests/local_onionshare_settings_dialog_no_tor_test.py
+++ b/tests/local_onionshare_settings_dialog_no_tor_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from onionshare import strings
@@ -14,6 +15,7 @@ class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
     def tearDownClass(cls):
         SettingsGuiBaseTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui_no_tor(self):
         self.gui.onion = OnionStub(False, False)
         self.gui.reload_settings()
diff --git a/tests/local_onionshare_settings_dialog_v3_tor_test.py b/tests/local_onionshare_settings_dialog_v3_tor_test.py
index cb10f8c9..1dd17c0f 100644
--- a/tests/local_onionshare_settings_dialog_v3_tor_test.py
+++ b/tests/local_onionshare_settings_dialog_v3_tor_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from onionshare import strings
@@ -14,6 +15,7 @@ class SettingsGuiTest(unittest.TestCase, SettingsGuiBaseTest):
     def tearDownClass(cls):
         SettingsGuiBaseTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui_v3_tor(self):
         self.gui.onion = OnionStub(True, True)
         self.gui.reload_settings()
diff --git a/tests/local_onionshare_share_mode_download_public_mode_test.py b/tests/local_onionshare_share_mode_download_public_mode_test.py
index d6dff13a..f9a9dc4c 100644
--- a/tests/local_onionshare_share_mode_download_public_mode_test.py
+++ b/tests/local_onionshare_share_mode_download_public_mode_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -15,6 +16,7 @@ class LocalShareModePublicModeTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(True, False)
diff --git a/tests/local_onionshare_share_mode_download_stay_open_test.py b/tests/local_onionshare_share_mode_download_stay_open_test.py
index 54d6de51..65304924 100644
--- a/tests/local_onionshare_share_mode_download_stay_open_test.py
+++ b/tests/local_onionshare_share_mode_download_stay_open_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -15,6 +16,7 @@ class LocalShareModeStayOpenTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(False, True)
diff --git a/tests/local_onionshare_share_mode_download_test.py b/tests/local_onionshare_share_mode_download_test.py
index ff182740..ea16683e 100644
--- a/tests/local_onionshare_share_mode_download_test.py
+++ b/tests/local_onionshare_share_mode_download_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -14,6 +15,7 @@ class LocalShareModeTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_tests(False, False)
diff --git a/tests/local_onionshare_share_mode_large_download_test.py b/tests/local_onionshare_share_mode_large_download_test.py
index 46e6df28..7d0595a2 100644
--- a/tests/local_onionshare_share_mode_large_download_test.py
+++ b/tests/local_onionshare_share_mode_large_download_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -14,6 +15,7 @@ class LocalShareModeLargeDownloadTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_large_file_tests(False, True)
diff --git a/tests/local_onionshare_share_mode_slug_persistent_test.py b/tests/local_onionshare_share_mode_slug_persistent_test.py
index a1cc6972..7254f3ff 100644
--- a/tests/local_onionshare_share_mode_slug_persistent_test.py
+++ b/tests/local_onionshare_share_mode_slug_persistent_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -18,6 +19,7 @@ class LocalShareModePersistentSlugTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_persistent_tests(False, True)
diff --git a/tests/local_onionshare_share_mode_timer_test.py b/tests/local_onionshare_share_mode_timer_test.py
index 41a6268d..e30ce4ec 100644
--- a/tests/local_onionshare_share_mode_timer_test.py
+++ b/tests/local_onionshare_share_mode_timer_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -16,6 +17,7 @@ class LocalShareModeTimerTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_timer_tests(False)
diff --git a/tests/local_onionshare_share_mode_timer_too_short_test.py b/tests/local_onionshare_share_mode_timer_too_short_test.py
index 41c30883..8d22048d 100644
--- a/tests/local_onionshare_share_mode_timer_too_short_test.py
+++ b/tests/local_onionshare_share_mode_timer_too_short_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 from PyQt5 import QtCore, QtTest
 
@@ -17,6 +18,7 @@ class LocalShareModeTimerTooShortTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_setup_tests()
diff --git a/tests/local_onionshare_share_mode_unreadable_file_test.py b/tests/local_onionshare_share_mode_unreadable_file_test.py
index 38a0e847..c74d7a0a 100644
--- a/tests/local_onionshare_share_mode_unreadable_file_test.py
+++ b/tests/local_onionshare_share_mode_unreadable_file_test.py
@@ -1,4 +1,5 @@
 #!/usr/bin/env python3
+import pytest
 import unittest
 
 from .GuiShareTest import GuiShareTest
@@ -14,6 +15,7 @@ class LocalShareModeUnReadableFileTest(unittest.TestCase, GuiShareTest):
     def tearDownClass(cls):
         GuiShareTest.tear_down()
 
+    @pytest.mark.gui
     def test_gui(self):
         self.run_all_common_setup_tests()
         self.run_all_share_mode_unreadable_file_tests()
diff --git a/tests/onionshare_790_cancel_on_second_share_test.py b/tests/onionshare_790_cancel_on_second_share_test.py
index b144edf3..4b7673bb 100644
--- a/tests/onionshare_790_cancel_on_second_share_test.py
+++ b/tests/onionshare_790_cancel_on_second_share_test.py
@@ -9,7 +9,7 @@ class ShareModeCancelSecondShareTest(unittest.TestCase, TorGuiShareTest):
     @classmethod
     def setUpClass(cls):
         test_settings = {
-            "close_after_first_download": True 
+            "close_after_first_download": True
         }
         cls.gui = TorGuiShareTest.set_up(test_settings)
 
@@ -17,6 +17,7 @@ class ShareModeCancelSecondShareTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_receive_mode_upload_public_mode_test.py b/tests/onionshare_receive_mode_upload_public_mode_test.py
index 275e5953..3c733f0a 100644
--- a/tests/onionshare_receive_mode_upload_public_mode_test.py
+++ b/tests/onionshare_receive_mode_upload_public_mode_test.py
@@ -17,6 +17,7 @@ class ReceiveModeTest(unittest.TestCase, TorGuiReceiveTest):
     def tearDownClass(cls):
         TorGuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_receive_mode_upload_test.py b/tests/onionshare_receive_mode_upload_test.py
index f9914659..493cacc7 100644
--- a/tests/onionshare_receive_mode_upload_test.py
+++ b/tests/onionshare_receive_mode_upload_test.py
@@ -16,6 +16,7 @@ class ReceiveModeTest(unittest.TestCase, TorGuiReceiveTest):
     def tearDownClass(cls):
         TorGuiReceiveTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_cancel_share_test.py b/tests/onionshare_share_mode_cancel_share_test.py
index 5f4d6fb3..ed28ddd7 100644
--- a/tests/onionshare_share_mode_cancel_share_test.py
+++ b/tests/onionshare_share_mode_cancel_share_test.py
@@ -15,6 +15,7 @@ class ShareModeCancelTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_download_public_mode_test.py b/tests/onionshare_share_mode_download_public_mode_test.py
index 672603ce..eb9adb1e 100644
--- a/tests/onionshare_share_mode_download_public_mode_test.py
+++ b/tests/onionshare_share_mode_download_public_mode_test.py
@@ -16,6 +16,7 @@ class ShareModePublicModeTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_download_stay_open_test.py b/tests/onionshare_share_mode_download_stay_open_test.py
index e7e64083..93a41f1f 100644
--- a/tests/onionshare_share_mode_download_stay_open_test.py
+++ b/tests/onionshare_share_mode_download_stay_open_test.py
@@ -16,6 +16,7 @@ class ShareModeStayOpenTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_download_test.py b/tests/onionshare_share_mode_download_test.py
index 7d414e5d..ac3dee76 100644
--- a/tests/onionshare_share_mode_download_test.py
+++ b/tests/onionshare_share_mode_download_test.py
@@ -15,6 +15,7 @@ class ShareModeTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_persistent_test.py b/tests/onionshare_share_mode_persistent_test.py
index 86b61a81..13588a68 100644
--- a/tests/onionshare_share_mode_persistent_test.py
+++ b/tests/onionshare_share_mode_persistent_test.py
@@ -20,6 +20,7 @@ class ShareModePersistentSlugTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_stealth_test.py b/tests/onionshare_share_mode_stealth_test.py
index b16669e6..bb9114a6 100644
--- a/tests/onionshare_share_mode_stealth_test.py
+++ b/tests/onionshare_share_mode_stealth_test.py
@@ -17,6 +17,7 @@ class ShareModeStealthTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_timer_test.py b/tests/onionshare_share_mode_timer_test.py
index a13d2d80..7f636a71 100644
--- a/tests/onionshare_share_mode_timer_test.py
+++ b/tests/onionshare_share_mode_timer_test.py
@@ -17,6 +17,7 @@ class ShareModeTimerTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_tor_connection_killed_test.py b/tests/onionshare_share_mode_tor_connection_killed_test.py
index 62513a12..cf48df3d 100644
--- a/tests/onionshare_share_mode_tor_connection_killed_test.py
+++ b/tests/onionshare_share_mode_tor_connection_killed_test.py
@@ -11,6 +11,7 @@ class ShareModeTorConnectionKilledTest(unittest.TestCase, TorGuiShareTest):
         }
         cls.gui = TorGuiShareTest.set_up(test_settings)
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()
diff --git a/tests/onionshare_share_mode_v2_onion_test.py b/tests/onionshare_share_mode_v2_onion_test.py
index c932abf9..18f5f058 100644
--- a/tests/onionshare_share_mode_v2_onion_test.py
+++ b/tests/onionshare_share_mode_v2_onion_test.py
@@ -16,6 +16,7 @@ class ShareModeV2OnionTest(unittest.TestCase, TorGuiShareTest):
     def tearDownClass(cls):
         TorGuiShareTest.tear_down()
 
+    @pytest.mark.gui
     @pytest.mark.tor
     def test_gui(self):
         self.run_all_common_setup_tests()

From f913037dee763d6f181cda37deefe95560651f3d Mon Sep 17 00:00:00 2001
From: Micah Lee <micah@micahflee.com>
Date: Tue, 15 Jan 2019 21:54:39 -0800
Subject: [PATCH 3/5] Make CircleCI run GUI tests

---
 .circleci/config.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 70fa3b7c..22458d70 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -15,7 +15,7 @@ jobs:
   test-3.5: &test-template
     docker:
       - image: circleci/python:3.5.6
-      
+
     working_directory: ~/repo
 
     steps:
@@ -33,7 +33,7 @@ jobs:
       # run tests!
       - run:
           name: run flake tests
-          command: | 
+          command: |
             # stop the build if there are Python syntax errors or undefined names
             flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
             # exit-zero treats all errors as warnings.  The GitHub editor is 127 chars wide
@@ -42,7 +42,7 @@ jobs:
       - run:
           name: run tests
           command: |
-            xvfb-run pytest --cov=onionshare --cov=onionshare_gui --cov-report=term-missing -vvv tests/
+            xvfb-run pytest --cov=onionshare --cov=onionshare_gui --cov-report=term-missing -vvv tests/ --rungui
 
   test-3.6:
     <<: *test-template

From 4168f477c8a275bee3160131b6ce58fc542b99f1 Mon Sep 17 00:00:00 2001
From: Micah Lee <micah@micahflee.com>
Date: Fri, 18 Jan 2019 14:37:18 -0800
Subject: [PATCH 4/5] Reorder args when running tests in CircleCI

---
 .circleci/config.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 22458d70..accbc808 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -42,7 +42,7 @@ jobs:
       - run:
           name: run tests
           command: |
-            xvfb-run pytest --cov=onionshare --cov=onionshare_gui --cov-report=term-missing -vvv tests/ --rungui
+            xvfb-run pytest --rungui --cov=onionshare --cov=onionshare_gui --cov-report=term-missing -vvv tests/
 
   test-3.6:
     <<: *test-template

From e432479c96c9b48cf6122630227af5911ce15cc3 Mon Sep 17 00:00:00 2001
From: Micah Lee <micah@micahflee.com>
Date: Fri, 18 Jan 2019 14:39:25 -0800
Subject: [PATCH 5/5] Update tests section in BUILD.md to give instructions on
 using --rungui to run GUI tests

---
 BUILD.md | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/BUILD.md b/BUILD.md
index 1e135251..6073d1a9 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -155,10 +155,16 @@ Then you can run `pytest` against the `tests/` directory.
 pytest tests/
 ```
 
+You can run GUI tests like this:
+
+```sh
+pytest --rungui tests/
+```
+
 If you would like to also run the GUI unit tests in 'tor' mode, start Tor Browser in the background, then run:
 
 ```sh
-pytest --runtor tests/
+pytest --rungui --runtor tests/
 ```
 
 Keep in mind that the Tor tests take a lot longer to run than local mode, but they are also more comprehensive.
@@ -166,5 +172,5 @@ Keep in mind that the Tor tests take a lot longer to run than local mode, but th
 You can also choose to wrap the tests in `xvfb-run` so that a ton of OnionShare windows don't pop up on your desktop (you may need to install the `xorg-x11-server-Xvfb` package), like this:
 
 ```sh
-xvfb-run pytest tests/
+xvfb-run pytest --rungui tests/
 ```