From 9ada049a16b55af17e3354b7fe8ac439c6e6469d Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 20:51:48 -0500 Subject: [PATCH 01/11] added geek base case --- qa327_test/frontend/geek_base.py | 32 ++++++++++ qa327_test/frontend/test_r1.py | 19 +----- .../frontend/{test_R2.py => test_r2.py} | 59 ++++++------------- qa327_test/frontend/test_r3.py | 25 +------- 4 files changed, 54 insertions(+), 81 deletions(-) create mode 100644 qa327_test/frontend/geek_base.py rename qa327_test/frontend/{test_R2.py => test_r2.py} (90%) diff --git a/qa327_test/frontend/geek_base.py b/qa327_test/frontend/geek_base.py new file mode 100644 index 0000000..105f2bc --- /dev/null +++ b/qa327_test/frontend/geek_base.py @@ -0,0 +1,32 @@ +from seleniumbase import BaseCase +from werkzeug.security import generate_password_hash +from qa327_test.conftest import base_url +from qa327.models import User + +# Mock a sample user +TEST_USER = User( + email='test_frontend@test.com', + name='test_frontend', + password=generate_password_hash('test_frontend'), + balance=140 +) + +class GeekBaseCase(BaseCase): + ''' + Selenium base case with some + GeekSeek utilities + ''' + + def assert_flash(self, text): + '''asserts that message exists in flashes''' + for flash_dom in self.find_elements('.flash'): + if flash_dom.text == text: + return + raise AssertionError(f'Flash not found for text "{text}"') + + def login_test_user(self): + '''login our test user''' + self.open(base_url+'/login') + self.input('#email', TEST_USER.email) + self.input('#password', 'test_frontend') + self.click('#btn-submit') \ No newline at end of file diff --git a/qa327_test/frontend/test_r1.py b/qa327_test/frontend/test_r1.py index 3f1b6e8..01f91de 100644 --- a/qa327_test/frontend/test_r1.py +++ b/qa327_test/frontend/test_r1.py @@ -8,31 +8,16 @@ from qa327_test.conftest import base_url from qa327.models import User - -# Mock a sample user -TEST_USER = User( - email='test_frontend@test.com', - name='test_frontend', - password=generate_password_hash('test_frontend'), - balance=140 -) +from qa327_test.frontend.geek_base import GeekBaseCase, TEST_USER INVALID_EMAILS = ['test_frontendtest.com', 'test_frontend@.com', 'test\frontend@test.com'] - INVALID_PASSWORDS = ['Pass!', 'password123!', 'PASSWORD123!', 'Password123'] -class R1Test(BaseCase): +class R1Test(GeekBaseCase): ''' Contains test cases specific to R1 ''' - def login_test_user(self): - '''login our test user''' - self.open(base_url+'/login') - self.input('#email', TEST_USER.email) - self.input('#password', 'test_frontend') - self.click('#btn-submit') - def test_login_redirects(self, *_): '''see r1.1''' self.open(base_url) diff --git a/qa327_test/frontend/test_R2.py b/qa327_test/frontend/test_r2.py similarity index 90% rename from qa327_test/frontend/test_R2.py rename to qa327_test/frontend/test_r2.py index e2c7a69..8555fa3 100644 --- a/qa327_test/frontend/test_R2.py +++ b/qa327_test/frontend/test_r2.py @@ -4,28 +4,20 @@ from unittest.mock import patch from werkzeug.security import generate_password_hash -from seleniumbase import BaseCase -from qa327_test.conftest import base_url - -import qa327.models - -# Defines user class to make testing more streamlined -class User: - def __init__(self, email=None, name=None, password=None): - self.email = email - self.name = name - self.password = password +from qa327.models import User +from qa327_test.conftest import base_url +from qa327_test.frontend.geek_base import GeekBaseCase # Defines test information -TEST_USER_A = qa327.models.User( +TEST_USER_A = User( email='test_frontend@test.com', name='test_frontend', password=generate_password_hash('Password123!', method='sha256'), balance=5000 ) -TEST_USER_B = qa327.models.User( +TEST_USER_B = User( email='test_frontend@test.com', name='test_frontend', password='Password123!' @@ -38,20 +30,26 @@ def __init__(self, email=None, name=None, password=None): password='Password123!' ) -INVALID_USER_NAME_FORMATS = ['', 'test_frontend123!', ' test_frontend123', - 'test_frontend123 '] +INVALID_USER_NAME_FORMATS = [ + '', 'test_frontend123!', + ' test_frontend123', 'test_frontend123 ' +] INVALID_USER_NAME_LENGTHS = ['te', 'test_frontend1234567890'] -INVALID_USER_EMAILS = ['', 'test_frontendtest.com', 'test_frontend@testcom', - '.test_frontend@test.com'] +INVALID_USER_EMAILS = [ + '', 'test_frontendtest.com', + 'test_frontend@testcom', '.test_frontend@test.com' +] -INVALID_USER_PASSWORDS = ['', 'Pass!', 'password123!', 'PASSWORD123!', - 'Password123'] +INVALID_USER_PASSWORDS = [ + '', 'Pass!', 'password123!', + 'PASSWORD123!','Password123' +] MISMATCHED_PASSWORD2 = 'Password123! ' -class R2Test(BaseCase): +class R2Test(GeekBaseCase): ''' Contains test cases specific to R2 ''' @@ -71,27 +69,6 @@ def register_test_user(self, *_): # Submits the inputted information self.click('#register-submit') - - def login_test_user(self): - '''login our test user''' - # Opens login page - self.open(base_url+'/login') - - # Logins in with user information - self.input('#email', TEST_USER_A.email) - self.input('#password', VALID_USER.password) - - # Submits the inputted information - self.click('#btn-submit') - - def assert_flash(self, text): - '''asserts that message exists in flashes''' - for flash_dom in self.find_elements('.flash'): - if flash_dom.text == text: - return - raise AssertionError(f'Flash not found for text "{text}"') - - @patch('qa327.backend.get_user', return_value=TEST_USER_A) def test_r2_1(self, *_): ''' diff --git a/qa327_test/frontend/test_r3.py b/qa327_test/frontend/test_r3.py index 888d551..a9f7024 100644 --- a/qa327_test/frontend/test_r3.py +++ b/qa327_test/frontend/test_r3.py @@ -8,14 +8,7 @@ from qa327_test.conftest import base_url from qa327.models import User - -# Moch a sample user -TEST_USER = User( - email='test_frontend@test.com', - name='test_frontend', - password=generate_password_hash('test_frontend'), - balance=140 -) +from qa327_test.frontend.geek_base import GeekBaseCase, TEST_USER # Moch some sample tickets TEST_TICKETS = [ @@ -24,25 +17,11 @@ ] -class R3Test(BaseCase): +class R3Test(GeekBaseCase): ''' Contains test cases specific to R3 ''' - def login_test_user(self): - '''login our test user''' - self.open(base_url+'/login') - self.input('#email', TEST_USER.email) - self.input('#password', 'test_frontend') - self.click('#btn-submit') - - def assert_flash(self, text): - '''asserts that message exists in flashes''' - for flash_dom in self.find_elements('.flash'): - if flash_dom.text == text: - return - raise AssertionError(f'Flash not found for text "{text}"') - def test_login_redirects(self, *_): '''see r3.1''' self.open(base_url) From 22489262237ce01a28f3344e31ccf538a8b7d2b3 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:08:40 -0500 Subject: [PATCH 02/11] generalized login function --- qa327_test/frontend/geek_base.py | 6 +++--- qa327_test/frontend/test_r2.py | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/qa327_test/frontend/geek_base.py b/qa327_test/frontend/geek_base.py index 105f2bc..03b1dfe 100644 --- a/qa327_test/frontend/geek_base.py +++ b/qa327_test/frontend/geek_base.py @@ -24,9 +24,9 @@ def assert_flash(self, text): return raise AssertionError(f'Flash not found for text "{text}"') - def login_test_user(self): + def login_test_user(self, email=TEST_USER.email, password='test_frontend'): '''login our test user''' self.open(base_url+'/login') - self.input('#email', TEST_USER.email) - self.input('#password', 'test_frontend') + self.input('#email', email) + self.input('#password', password) self.click('#btn-submit') \ No newline at end of file diff --git a/qa327_test/frontend/test_r2.py b/qa327_test/frontend/test_r2.py index 8555fa3..4a21cda 100644 --- a/qa327_test/frontend/test_r2.py +++ b/qa327_test/frontend/test_r2.py @@ -77,7 +77,10 @@ def test_r2_1(self, *_): ''' # Logs in user to - self.login_test_user() + self.login_test_user( + email=TEST_USER_A.email, + password='Password123!' + ) # Opens the user profile page / self.open(base_url) @@ -375,7 +378,10 @@ def test_r2_11(self, get_user_function, *_): get_user_function.return_value = TEST_USER_A # Logs in user with newly registered user - self.login_test_user() + self.login_test_user( + email=TEST_USER_A.email, + password='Password123!' + ) # Opens the user profile page / self.open(base_url) From 281735b2bedd66424b7d67068e26f276fdac2580 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:10:51 -0500 Subject: [PATCH 03/11] adjusted comments --- qa327_test/frontend/test_r1.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qa327_test/frontend/test_r1.py b/qa327_test/frontend/test_r1.py index 01f91de..f178172 100644 --- a/qa327_test/frontend/test_r1.py +++ b/qa327_test/frontend/test_r1.py @@ -56,7 +56,7 @@ def test_form_password_missing(self, *_): self.open(base_url+'/login') self.input('#email', TEST_USER.email) self.click('#btn-submit') - #leave password empty + # leave password empty message = self.driver.find_element_by_id('password') assert message.get_attribute('validationMessage') == 'Please fill out this field.' @@ -66,7 +66,7 @@ def test_form_email_missing(self, *_): self.open(base_url+'/login') self.input('#password', 'test_frontend') self.click('#btn-submit') - #leave password empty + # leave password empty message = self.driver.find_element_by_id('email') assert message.get_attribute('validationMessage') == 'Please fill out this field.' @@ -78,7 +78,7 @@ def test_email_rfc_specs(self, *_): def test_invalid_email_rfc_specs(self, *_): '''see r1.7 (negative)''' - #invalid email format + # invalid email format for invalid_email in INVALID_EMAILS: self.open(base_url+'/login') self.input('#email', invalid_email) @@ -96,7 +96,7 @@ def test_password_complexity(self, *_): def test_invalid_password_complexity(self, *_): '''see r1.8 (negative)''' - #invalid password complexity + # invalid password complexity for invalid_pass in INVALID_PASSWORDS: self.open(base_url+'/login') self.input('#email', TEST_USER.email) From 7c5b1a80f3b543a4370279e7acf9856b61ca5a97 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:11:02 -0500 Subject: [PATCH 04/11] removed Test User B --- qa327_test/frontend/test_r2.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/qa327_test/frontend/test_r2.py b/qa327_test/frontend/test_r2.py index 4a21cda..15eb4d3 100644 --- a/qa327_test/frontend/test_r2.py +++ b/qa327_test/frontend/test_r2.py @@ -17,13 +17,6 @@ balance=5000 ) -TEST_USER_B = User( - email='test_frontend@test.com', - name='test_frontend', - password='Password123!' -) - - VALID_USER = User( email='test_frontend@test.com', name='test_frontend', @@ -334,7 +327,7 @@ def test_r2_9(self, *_): assert self.get_current_url() == base_url+'/login' - @patch('qa327.backend.get_user', return_value=TEST_USER_B) + @patch('qa327.backend.get_user', return_value=VALID_USER) def test_r2_10(self, *_): ''' 10) Test Case R2.10 - If the email already exists, show message From 2f4e3dce0d50afb68760162d6a51fc7b849cadcf Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:12:43 -0500 Subject: [PATCH 05/11] adjusted r7 and r8 --- qa327_test/frontend/test_r7.py | 18 ++---------------- .../frontend/{test_404.py => test_r8.py} | 6 +++--- 2 files changed, 5 insertions(+), 19 deletions(-) rename qa327_test/frontend/{test_404.py => test_r8.py} (77%) diff --git a/qa327_test/frontend/test_r7.py b/qa327_test/frontend/test_r7.py index 700b2f0..eec2082 100644 --- a/qa327_test/frontend/test_r7.py +++ b/qa327_test/frontend/test_r7.py @@ -8,29 +8,15 @@ from qa327.models import User from qa327_test.conftest import base_url +from qa327_test.frontend.geek_base import GeekBaseCase, TEST_USER -#Mock a sample user -TEST_USER = User( - email='test_frontend@test.com', - name='test_frontend', - password=generate_password_hash('test_frontend'), - balance=140 -) - -class R7Test(BaseCase): +class R7Test(GeekBaseCase): ''' Contains test cases specific to R7. Test only test the frontend portion, and will patch the backend specific values ''' - def login_test_user(self): - '''login our test user''' - self.open(base_url+'/login') - self.input('#email', TEST_USER.email) - self.input('#password', 'test_frontend') - self.click('#btn-submit') - @patch('qa327.backend.get_user', return_value=TEST_USER) def test_logout_redirect(self, *_): diff --git a/qa327_test/frontend/test_404.py b/qa327_test/frontend/test_r8.py similarity index 77% rename from qa327_test/frontend/test_404.py rename to qa327_test/frontend/test_r8.py index 1f8b587..0f2e439 100644 --- a/qa327_test/frontend/test_404.py +++ b/qa327_test/frontend/test_r8.py @@ -1,10 +1,10 @@ -import pytest +from unittest.mock import patch from seleniumbase import BaseCase +from qa327_test.frontend.geek_base import GeekBaseCase from qa327_test.conftest import base_url -from unittest.mock import patch -class Http404Test(BaseCase): +class R8Test(GeekBaseCase): def test_404_text(self, *_): # open home page From 6253b9299a246761c5005dfab5533cdc3fb0a63f Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:16:04 -0500 Subject: [PATCH 06/11] pytest uses different port --- qa327_test/conftest.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qa327_test/conftest.py b/qa327_test/conftest.py index 4ee7e86..febcd42 100644 --- a/qa327_test/conftest.py +++ b/qa327_test/conftest.py @@ -9,14 +9,17 @@ import threading from werkzeug.serving import make_server +# separate port allows tests to be run while hosting +# actual app +FLASK_TEST_PORT = 8082 -base_url = 'http://localhost:{}'.format(FLASK_PORT) +base_url = 'http://localhost:{}'.format(FLASK_TEST_PORT) class ServerThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) - self.srv = make_server('127.0.0.1', FLASK_PORT, app) + self.srv = make_server('127.0.0.1', FLASK_TEST_PORT, app) self.ctx = app.app_context() self.ctx.push() From 5d3ea17d6045aba0a406fdd367030585ca17d7b9 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 21:17:37 -0500 Subject: [PATCH 07/11] added docstring --- qa327_test/frontend/test_r7.py | 1 - qa327_test/frontend/test_r8.py | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/qa327_test/frontend/test_r7.py b/qa327_test/frontend/test_r7.py index eec2082..98660da 100644 --- a/qa327_test/frontend/test_r7.py +++ b/qa327_test/frontend/test_r7.py @@ -18,7 +18,6 @@ class R7Test(GeekBaseCase): ''' @patch('qa327.backend.get_user', return_value=TEST_USER) - def test_logout_redirect(self, *_): '''see r7.1''' self.open(base_url) diff --git a/qa327_test/frontend/test_r8.py b/qa327_test/frontend/test_r8.py index 0f2e439..08e78d2 100644 --- a/qa327_test/frontend/test_r8.py +++ b/qa327_test/frontend/test_r8.py @@ -5,8 +5,14 @@ from qa327_test.conftest import base_url class R8Test(GeekBaseCase): + ''' + contains test cases for R8 requirements + ''' def test_404_text(self, *_): + ''' + verifies that our 404 page is actually displayed + ''' # open home page self.open(base_url+'/randomtest') # test if the page loads correctly From 39732a260539e8bb979b7460fac72d44e6006720 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 22:58:10 -0500 Subject: [PATCH 08/11] formatting --- qa327_test/frontend/test_r2.py | 2 +- qa327_test/frontend/test_r3.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/qa327_test/frontend/test_r2.py b/qa327_test/frontend/test_r2.py index 15eb4d3..8f0850e 100644 --- a/qa327_test/frontend/test_r2.py +++ b/qa327_test/frontend/test_r2.py @@ -24,7 +24,7 @@ ) INVALID_USER_NAME_FORMATS = [ - '', 'test_frontend123!', + '', 'test_frontend123!', ' test_frontend123', 'test_frontend123 ' ] diff --git a/qa327_test/frontend/test_r3.py b/qa327_test/frontend/test_r3.py index a9f7024..3c07a60 100644 --- a/qa327_test/frontend/test_r3.py +++ b/qa327_test/frontend/test_r3.py @@ -16,7 +16,6 @@ {'name': 't2', 'price': '90', 'owner': 'geek', 'count': 3}, ] - class R3Test(GeekBaseCase): ''' Contains test cases specific to R3 From 985df65e1bfb6c7471ecd324443d2d1af032db20 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 23:29:05 -0500 Subject: [PATCH 09/11] properly mock backend methods --- qa327/backend.py | 9 +++++++++ qa327/frontend.py | 12 ++++++------ qa327_test/frontend/test_r3.py | 3 +++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/qa327/backend.py b/qa327/backend.py index 78b6c62..3dead58 100644 --- a/qa327/backend.py +++ b/qa327/backend.py @@ -49,3 +49,12 @@ def register_user(email, name, password, password2): def get_all_tickets(): """Going to be implemented when /sell and /buy is implemented""" return [] + +def buy_ticket(form): + raise "TODO" + +def sell_ticket(form): + raise 'TODO' + +def update_ticket(form): + raise 'TODO' \ No newline at end of file diff --git a/qa327/frontend.py b/qa327/frontend.py index da37f89..438df5d 100644 --- a/qa327/frontend.py +++ b/qa327/frontend.py @@ -110,18 +110,18 @@ def login_post(): @app.route('/buy', methods=['POST']) def buy_post(): - flash('ticket bought successfully') - return redirect('/',303) + flash(bn.buy_ticket(request.form)) + return redirect('/', 303) @app.route('/sell', methods=['POST']) def sell_post(): - flash('ticket sold successfully') - return redirect('/',303) + flash(bn.sell_ticket(request.form)) + return redirect('/', 303) @app.route('/update', methods=['POST']) def update_post(): - flash('ticket updated successfully') - return redirect('/',303) + flash(bn.update_ticket(request.form)) + return redirect('/', 303) @app.route('/logout') diff --git a/qa327_test/frontend/test_r3.py b/qa327_test/frontend/test_r3.py index 3c07a60..8fcc6c1 100644 --- a/qa327_test/frontend/test_r3.py +++ b/qa327_test/frontend/test_r3.py @@ -102,6 +102,7 @@ def test_update_form(self, *_): self.assert_element('#update-ticket-expiration-date') @patch('qa327.backend.get_user', return_value=TEST_USER) + @patch('qa327.backend.sell_ticket',return_value='ticket sold successfully') def test_sell_posts(self, *_): '''see r3.9''' self.login_test_user() @@ -114,6 +115,7 @@ def test_sell_posts(self, *_): self.assert_flash('ticket sold successfully') @patch('qa327.backend.get_user', return_value=TEST_USER) + @patch('qa327.backend.buy_ticket',return_value='ticket bought successfully') def test_buy_posts(self, *_): '''see r3.10''' self.login_test_user() @@ -124,6 +126,7 @@ def test_buy_posts(self, *_): self.assert_flash('ticket bought successfully') @patch('qa327.backend.get_user', return_value=TEST_USER) + @patch('qa327.backend.update_ticket', return_value='ticket updated successfully') def test_update_posts(self, *_): '''see r3.11''' self.login_test_user() From 598a7485f737c4a8e670b2b876c29b94479c5929 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 23:31:41 -0500 Subject: [PATCH 10/11] added docstrings --- qa327/backend.py | 3 +++ qa327/frontend.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/qa327/backend.py b/qa327/backend.py index 3dead58..50f0f96 100644 --- a/qa327/backend.py +++ b/qa327/backend.py @@ -51,10 +51,13 @@ def get_all_tickets(): return [] def buy_ticket(form): + '''buy a ticket, returns a message''' raise "TODO" def sell_ticket(form): + '''sell a ticket, returns a message''' raise 'TODO' def update_ticket(form): + '''update a ticket, returns a message''' raise 'TODO' \ No newline at end of file diff --git a/qa327/frontend.py b/qa327/frontend.py index 438df5d..e74f61e 100644 --- a/qa327/frontend.py +++ b/qa327/frontend.py @@ -110,16 +110,19 @@ def login_post(): @app.route('/buy', methods=['POST']) def buy_post(): + '''buy a ticket using the HTML form''' flash(bn.buy_ticket(request.form)) return redirect('/', 303) @app.route('/sell', methods=['POST']) def sell_post(): + '''sell a ticket using the HTML form''' flash(bn.sell_ticket(request.form)) return redirect('/', 303) @app.route('/update', methods=['POST']) def update_post(): + '''update a ticket using the HTML form''' flash(bn.update_ticket(request.form)) return redirect('/', 303) From ed3eb7234c6d57c9b646c028f2a6e15c94b75385 Mon Sep 17 00:00:00 2001 From: Ted Brownlow Date: Mon, 16 Nov 2020 23:35:58 -0500 Subject: [PATCH 11/11] followed linter --- qa327_test/frontend/test_r3.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/qa327_test/frontend/test_r3.py b/qa327_test/frontend/test_r3.py index 8fcc6c1..840704d 100644 --- a/qa327_test/frontend/test_r3.py +++ b/qa327_test/frontend/test_r3.py @@ -3,11 +3,8 @@ ''' from unittest.mock import patch -from seleniumbase import BaseCase -from werkzeug.security import generate_password_hash from qa327_test.conftest import base_url -from qa327.models import User from qa327_test.frontend.geek_base import GeekBaseCase, TEST_USER # Moch some sample tickets @@ -102,7 +99,7 @@ def test_update_form(self, *_): self.assert_element('#update-ticket-expiration-date') @patch('qa327.backend.get_user', return_value=TEST_USER) - @patch('qa327.backend.sell_ticket',return_value='ticket sold successfully') + @patch('qa327.backend.sell_ticket', return_value='ticket sold successfully') def test_sell_posts(self, *_): '''see r3.9''' self.login_test_user() @@ -115,7 +112,7 @@ def test_sell_posts(self, *_): self.assert_flash('ticket sold successfully') @patch('qa327.backend.get_user', return_value=TEST_USER) - @patch('qa327.backend.buy_ticket',return_value='ticket bought successfully') + @patch('qa327.backend.buy_ticket', return_value='ticket bought successfully') def test_buy_posts(self, *_): '''see r3.10''' self.login_test_user() @@ -136,4 +133,4 @@ def test_update_posts(self, *_): self.input('#update-ticket-price', 'dont-care') self.input('#update-ticket-expiration-date', 'dont-care') self.click('#update-submit') - self.assert_flash('ticket updated successfully') \ No newline at end of file + self.assert_flash('ticket updated successfully')