Merge lp:~elopio/u1-test-utils/log_page_errors into lp:u1-test-utils

Proposed by Leo Arias
Status: Merged
Approved by: Leo Arias
Approved revision: 52
Merged at revision: 42
Proposed branch: lp:~elopio/u1-test-utils/log_page_errors
Merge into: lp:u1-test-utils
Prerequisite: lp:~elopio/u1-test-utils/assert_page_errors
Diff against target: 223 lines (+92/-18)
4 files modified
requirements.txt (+1/-0)
u1testutils/sst/__init__.py (+38/-8)
u1testutils/sst/selftests/acceptance/test_page.py (+39/-6)
u1testutils/sst/selftests/unit/test_pages.py (+14/-4)
To merge this branch: bzr merge lp:~elopio/u1-test-utils/log_page_errors
Reviewer Review Type Date Requested Status
Corey Goldberg (community) Approve
Review via email: mp+157278@code.launchpad.net

Commit message

Add the errors present in the page to the log, in case the assertion that the page is open failed.

To post a comment you must log in.
Revision history for this message
Corey Goldberg (coreygoldberg) wrote :

nice. approved.

review: Approve
Revision history for this message
Leo Arias (elopio) wrote :
Download full text (3.5 KiB)

<cgoldberg> elopio, looking at log_page_errors
<cgoldberg> how come you needed beautiful soup for parsing that element?
<-> nessita-away is now known as nessita
<elopio> cgoldberg: like killing a fly with a bazooka? I find beautiful soup nice and handy to modify the html.
<elopio> would you do it differently?
<cgoldberg> i like beautifulsoup too :) but can't you just access it with sst?
<elopio> cgoldberg: but I'm using bs to edit the page before opening it with sst.
<elopio> just to avoid hardcoding a new complete html string.
<cgoldberg> elopio, i'm looking at diff line 161 specifically
<elopio> cgoldberg: yes, that yui3-error-visible element is not on the original page_source.
<cgoldberg> elopio, ohh.. you are using bs to build a dom, not read it
<elopio> I'm appending it with beautiful soup, to make it accessible for SST.
<cgoldberg> gotcha.. i thought you were using it to parse the dom and do assertions
<elopio> cgoldberg: no, I'm using a test double open page that can open it from a string. And from there, it's all SST.
<elopio> cgoldberg: I'm not sure if it's the best way though. Suggestions always welcome :)
<cgoldberg> hmm.. is BS already a dependency?
<cgoldberg> used elsewhere i mean
<elopio> cgoldberg: no, I added it in this branch. But I plan to extend the page object with stuff I have on u1, and it will be useful when I'm writing those tests.
<elopio> and it will not be a dependency for execution, just for testing.
<cgoldberg> ok. I was going to say I wouldn't add it, if it's only for this case. but if you plan on using it heavily elsewhere, it seems reasonable
<cgoldberg> elopio, what about lxml? do all projects already include that? (sso/pay do afaik)
<elopio> cgoldberg: I think it'll be useful.
<elopio> cgoldberg: beautifulsoup can use lxml parser, for speed improvements. But I find bs cleaner for what I'm doing
<cgoldberg> is beautifulsoup API nicer than lxml?
<cgoldberg> i haven't used either in quite a few years. i remember switching from bs to lxml for speed.. but this case speed isn't an issue... we just want the best parser/manipulator for testing.
<elopio> cgoldberg: I like it better. And it has some beautiful things that I thought would be useful for SST
<elopio> it can prettify the html that we sometimes print in the log.
<cgoldberg> cool. it looks bs is python3 compatible too.. so I'm +1 on it
<cgoldberg> just to throw one more idea into the mix.. have you ever used html5lib ?
<elopio> oh, well, lxml also has a pretty print.
<elopio> cgoldberg: I've just read about it. I wrote this code a couple of months ago, and now I just pasted it to this branch :)
<elopio> I think any of them can work. I have a preference for bs, but it's not strong and mostly subjective.
<cgoldberg> pretty formatted html out would be nice
<elopio> cgoldberg: so, if you prefer any other lib, I can switch without hard feelings ;)
<elopio> cgoldberg: I think html5lib doesn't have the pretty print. lxml and bs have it.
<cgoldberg> i don't have a strong preference.. that's why i'm asking too :) i just think whichever lib we go with, we should try to stick with in all our test tools/libs
<elopio> cgoldberg: I would go with bs using the lxml p...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'requirements.txt'
2--- requirements.txt 2013-03-26 23:14:30 +0000
3+++ requirements.txt 2013-04-05 06:08:22 +0000
4@@ -1,4 +1,5 @@
5 # Packages.
6+beautifulsoup4
7 django==1.4
8 mock
9 pep8
10
11=== modified file 'u1testutils/sst/__init__.py'
12--- u1testutils/sst/__init__.py 2013-04-05 06:08:22 +0000
13+++ u1testutils/sst/__init__.py 2013-04-05 06:08:22 +0000
14@@ -12,9 +12,14 @@
15 # You should have received a copy of the GNU General Public License along
16 # with this program. If not, see <http://www.gnu.org/licenses/>.
17
18+import logging
19+
20 import sst.actions
21
22
23+logger = logging.getLogger('User test')
24+
25+
26 class Page(object):
27 """Base class for the page objects used in acceptance testing.
28
29@@ -37,12 +42,31 @@
30 self.assert_page_is_open()
31
32 def assert_page_is_open(self):
33- """Assert that the page is open."""
34- self.assert_title()
35- if self.headings1:
36- self.assert_headings1()
37- if self.headings2:
38- self.assert_headings2()
39+ """Assert that the page is open and that no oops are displayed."""
40+ try:
41+ assert not self._is_oops_displayed(), \
42+ 'An oops error is displayed: {0}'.format(
43+ self._get_oops_element().text)
44+ self.assert_title()
45+ if self.headings1:
46+ self.assert_headings1()
47+ if self.headings2:
48+ self.assert_headings2()
49+ except AssertionError:
50+ self._log_errors()
51+ raise
52+
53+ def _is_oops_displayed(self):
54+ try:
55+ self._get_oops_element()
56+ return True
57+ except AssertionError:
58+ return False
59+
60+ def _get_oops_element(self):
61+ # TODO this works for U1. Does it work the same for pay and SSO?
62+ oops_class = 'yui3-error-visible'
63+ return sst.actions.get_element(css_class=oops_class)
64
65 def assert_title(self):
66 sst.actions.assert_title(self.title)
67@@ -58,10 +82,16 @@
68 'Actual elements texts: {1}'.format(
69 ', '.join(expected_texts), ', '.join(elements_text))
70
71- def _get_elements_text(self, tag):
72+ def _get_elements_text(self, tag=None, css_class=None):
73 get_text = lambda x: x.text
74- return map(get_text, sst.actions.get_elements(tag=tag))
75+ return map(get_text, sst.actions.get_elements(
76+ tag=tag, css_class=css_class))
77
78 def assert_headings2(self):
79 """Assert the h2 elements of the page."""
80 self._assert_elements_text('h2', self.headings2)
81+
82+ def _log_errors(self):
83+ if sst.actions.exists_element(css_class='error'):
84+ logger.error(
85+ ', '.join(self._get_elements_text(css_class='error')))
86
87=== modified file 'u1testutils/sst/selftests/acceptance/test_page.py'
88--- u1testutils/sst/selftests/acceptance/test_page.py 2013-04-05 06:08:22 +0000
89+++ u1testutils/sst/selftests/acceptance/test_page.py 2013-04-05 06:08:22 +0000
90@@ -15,8 +15,11 @@
91 import os
92 import tempfile
93
94+import bs4
95 import sst.runtests
96+from testtools.matchers import Contains
97
98+import u1testutils.logging
99 import u1testutils.sst
100
101
102@@ -28,9 +31,11 @@
103 # errors.
104 super(StringHTMLPage, self).__init__(check=False)
105
106- def open_page(self):
107+ def open_page(self, page_source=None):
108+ if not page_source:
109+ page_source = self.page_source
110 page_file = tempfile.NamedTemporaryFile(delete=False)
111- page_file.write(self.page_source)
112+ page_file.write(page_source)
113 page_file.close()
114 sst.actions.go_to('file://{0}'.format(page_file.name))
115 # We delete the temporary page file as it's not longer needed.
116@@ -56,9 +61,8 @@
117 self.page = StringHTMLPage(self.page_source)
118
119
120-class AssertPageTestCase(StringPageSSTTestCase):
121-
122- screenshots_on = True
123+class AssertPageTestCase(
124+ StringPageSSTTestCase, u1testutils.logging.LogHandlerTestCase):
125
126 page_source = (
127 """
128@@ -81,12 +85,12 @@
129 def setUp(self):
130 super(AssertPageTestCase, self).setUp()
131 self.page = StringHTMLPage(self.page_source)
132- self.page.open_page()
133
134 def test_correct_page_is_open(self):
135 self.page.title = 'Test title'
136 self.page.headings1 = ['Test h1 1', 'Test h1 2']
137 self.page.headings2 = ['Test h2 1', 'Test h2 2']
138+ self.page.open_page()
139 self.page.assert_page_is_open()
140
141 def test_wrong_title(self):
142@@ -95,6 +99,7 @@
143
144 def test_wrong_headings1_text(self):
145 self.page.headings1 = ['Test h1 1', 'Wrong h1']
146+ self.page.open_page()
147 error = self.assertRaises(AssertionError, self.page.assert_headings1)
148 self.assertEqual(
149 error.message,
150@@ -103,8 +108,36 @@
151
152 def test_wrong_headings2_text(self):
153 self.page.headings2 = ['Test h2 1', 'Wrong h2']
154+ self.page.open_page()
155 error = self.assertRaises(AssertionError, self.page.assert_headings2)
156 self.assertEqual(
157 error.message,
158 'Expected elements texts: Test h2 1, Wrong h2\n'
159 'Actual elements texts: Test h2 1, Test h2 2')
160+
161+ def test_assert_page_with_visible_oops(self):
162+ soup = bs4.BeautifulSoup(self.page_source)
163+ oops_element = soup.new_tag('div')
164+ oops_element['class'] = 'yui3-error-visible'
165+ oops_element.string = 'Test oops'
166+ soup.body.append(oops_element)
167+ # We don't need to make the assertions for the rest of the page.
168+ self.page.assert_title = lambda: None
169+ self.page.headings1 = []
170+ self.page.headings2 = []
171+ self.page.open_page(page_source=str(soup))
172+ error = self.assertRaises(
173+ AssertionError, self.page.assert_page_is_open)
174+ self.assertThat(error.message, Contains('Test oops'))
175+
176+ def test_assert_wrong_page_with_error(self):
177+ soup = bs4.BeautifulSoup(self.page_source)
178+ error_element = soup.new_tag('span')
179+ error_element['class'] = 'error'
180+ error_element.string = 'Test error'
181+ soup.body.append(error_element)
182+ self.page.title = 'Wrong title'
183+ self.page.open_page(page_source=str(soup))
184+ self.assertRaises(
185+ AssertionError, self.page.assert_page_is_open)
186+ self.assertLogLevelContains('ERROR', 'Test error')
187
188=== modified file 'u1testutils/sst/selftests/unit/test_pages.py'
189--- u1testutils/sst/selftests/unit/test_pages.py 2013-04-05 06:08:22 +0000
190+++ u1testutils/sst/selftests/unit/test_pages.py 2013-04-05 06:08:22 +0000
191@@ -30,18 +30,28 @@
192 Page(check=False)
193 assert not mock_assert.called
194
195+
196+class PageWithOnlyHeadingsAssertions(Page):
197+
198+ def assert_title(self):
199+ pass
200+
201+ def _is_oops_displayed(self):
202+ pass
203+
204+
205+class PageHeadingsTestCase(testtools.TestCase):
206+
207 def test_assert_page_without_headings1_check(self):
208 with mock.patch.object(Page, 'assert_headings1') as mock_assert:
209- page = Page(check=False)
210+ page = PageWithOnlyHeadingsAssertions(check=False)
211 page.headings1 = []
212- page.assert_title = lambda: None
213 page.assert_page_is_open()
214 assert not mock_assert.called
215
216 def test_assert_page_without_headings2_check(self):
217 with mock.patch.object(Page, 'assert_headings2') as mock_assert:
218- page = Page(check=False)
219+ page = PageWithOnlyHeadingsAssertions(check=False)
220 page.headings2 = []
221- page.assert_title = lambda: None
222 page.assert_page_is_open()
223 assert not mock_assert.called

Subscribers

People subscribed via source and target branches

to all changes: