Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions tests/assets/offscreenbuttons.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<style>
button {
position: absolute;
width: 100px;
height: 20px;
margin: 0;
}

body, html {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
position: relative;
}

div {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}

#btn0 { right: 0px; top: 0; }
#btn1 { right: -10px; top: 25px; }
#btn2 { right: -20px; top: 50px; }
#btn3 { right: -30px; top: 75px; }
#btn4 { right: -40px; top: 100px; }
#btn5 { right: -50px; top: 125px; }
#btn6 { right: -60px; top: 150px; }
#btn7 { right: -70px; top: 175px; }
#btn8 { right: -80px; top: 200px; }
#btn9 { right: -90px; top: 225px; }
#btn10 { right: -100px; top: 250px; }
</style>
<div>
<button id=btn0>0</button>
<button id=btn1>1</button>
<button id=btn2>2</button>
<button id=btn3>3</button>
<button id=btn4>4</button>
<button id=btn5>5</button>
<button id=btn6>6</button>
<button id=btn7>7</button>
<button id=btn8>8</button>
<button id=btn9>9</button>
<button id=btn10>10</button>
</div>
<script>
window.addEventListener('DOMContentLoaded', () => {
for (const button of Array.from(document.querySelectorAll('button')))
button.addEventListener('click', () => console.log('button #' + button.textContent + ' clicked'), false);
}, false);
</script>
11 changes: 10 additions & 1 deletion tests/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from contextlib import closing

import http.server
import os
import socket

def find_free_port():
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]

class Server:
def __init__(self):
self.PORT = 8907
self.PORT = find_free_port()
self.EMPTY_PAGE = f'http://localhost:{self.PORT}/empty.html'
self.PREFIX = f'http://localhost:{self.PORT}'
self.CROSS_PROCESS_PREFIX = f'http://127.0.0.1:{self.PORT}'
Expand Down
138 changes: 131 additions & 7 deletions tests/test_element_handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,144 @@ async def test_hover_when_node_is_removed(page, server):
await button.hover()
assert await page.evaluate('document.querySelector("button:hover").id') == 'button-6'

async def test_should_fill_input(page, server):
async def test_scroll(page, server):
await page.goto(server.PREFIX + '/offscreenbuttons.html')
for i in range(11):
button = await page.querySelector(f'#btn{i}')
before = await button.evaluate('''button => {
return button.getBoundingClientRect().right - window.innerWidth
}''')

assert before == 10 * i
await button.scrollIntoViewIfNeeded()
after = await button.evaluate('''button => {
return button.getBoundingClientRect().right - window.innerWidth
}''')

assert after <= 0
await page.evaluate('() => window.scrollTo(0, 0)')

async def test_scroll_should_throw_for_detached_element(page, server):
await page.setContent('<div>Hello</div>')
div = await page.querySelector('div')
await div.evaluate('div => div.remove()')
try:
await div.scrollIntoViewIfNeeded()
except Error as e:
error = e
assert 'Element is not attached to the DOM' in error.message

async def waiting_helper(page, after):
div = await page.querySelector('div')
done = list()
async def scroll():
done.append(False)
await div.scrollIntoViewIfNeeded()
done.append(True)
promise = asyncio.ensure_future(scroll())
await page.evaluate('() => new Promise(f => setTimeout(f, 1000))')
assert done == [False]
await div.evaluate(after)
await promise
assert done == [False, True]

async def test_should_wait_for_display_none_to_become_visible(page):
await page.setContent('<div style="display:none">Hello</div>')
await waiting_helper(page, 'div => div.style.display = "block"')

async def test_should_wait_for_display_contents_to_become_visible(page):
await page.setContent('<div style="display:contents">Hello</div>')
await waiting_helper(page, 'div => div.style.display = "block"')

async def test_should_wait_for_visibility_hidden_to_become_visible(page):
await page.setContent('<div style="visibility:hidden">Hello</div>')
await waiting_helper(page, 'div => div.style.visibility = "visible"')

async def test_should_wait_for_zero_sized_element_to_become_visible(page):
await page.setContent('<div style="height:0">Hello</div>')
await waiting_helper(page, 'div => div.style.height = "100px"')

async def test_should_wait_for_nested_display_none_to_become_visible(page):
await page.setContent('<span style="display:none"><div>Hello</div></span>')
await waiting_helper(page, 'div => div.parentElement.style.display = "block"')

async def test_should_timeout_waiting_for_visible(page):
await page.setContent('<div style="display:none">Hello</div>')
div = await page.querySelector('div')
try:
error = await div.scrollIntoViewIfNeeded(timeout=3000)
except Error as e:
error = e
assert 'element is not visible' in error.message

async def test_fill_input(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
handle = await page.querySelector('input')
await handle.fill('some value')
assert await page.evaluate('result') == 'some value'

async def test_should_fill_input_when_Node_is_removed(page, server):
async def test_fill_input_when_Node_is_removed(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
await page.evaluate('delete window["Node"]')
handle = await page.querySelector('input')
await handle.fill('some value')
assert await page.evaluate('result') == 'some value'

async def test_should_have_a_nice_preview(page, server):
async def test_select_textarea(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
textarea = await page.querySelector('textarea')
await textarea.evaluate('textarea => textarea.value = "some value"')
await textarea.selectText()
if False: # FFOX
assert await textarea.evaluate('el => el.selectionStart') == 0
assert await textarea.evaluate('el => el.selectionEnd') == 10
else:
assert await page.evaluate('() => window.getSelection().toString()') == 'some value'

async def test_select_input(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
input = await page.querySelector('input')
await input.evaluate('input => input.value = "some value"')
await input.selectText()
if False: # FFOX
assert await input.evaluate('el => el.selectionStart') == 0
assert await input.evaluate('el => el.selectionEnd') == 10
else:
assert await page.evaluate('() => window.getSelection().toString()') == 'some value'

async def test_select_text_select_plain_div(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
div = await page.querySelector('div.plain')
await div.selectText()
assert await page.evaluate('() => window.getSelection().toString()') == 'Plain div'

async def test_select_text_timeout_waiting_for_invisible_element(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
textarea = await page.querySelector('textarea')
await textarea.evaluate('e => e.style.display = "none"')
try:
await textarea.selectText(timeout=3000)
except Error as e:
error = e
assert 'element is not visible' in error.message

async def test_select_text_wait_for_visible(page, server):
await page.goto(server.PREFIX + '/input/textarea.html')
textarea = await page.querySelector('textarea')
await textarea.evaluate('textarea => textarea.value = "some value"')
await textarea.evaluate('e => e.style.display = "none"')
done = list()
async def select_text():
done.append(False)
await textarea.selectText(timeout=3000)
done.append(True)
promise = asyncio.ensure_future(select_text())
await page.evaluate('() => new Promise(f => setTimeout(f, 1000))')
await textarea.evaluate('e => e.style.display = "block"')
await promise
assert done == [False, True]

async def test_a_nice_preview(page, server):
await page.goto(f'{server.PREFIX}/dom.html')
outer = await page.querySelector('#outer')
inner = await page.querySelector('#inner')
Expand Down Expand Up @@ -355,26 +479,26 @@ async def test_text_content(page, server):
assert await handle.textContent() == 'Text,\nmore text'
assert await page.textContent('#inner') == 'Text,\nmore text'

async def test_should_check_the_box(page):
async def test_check_the_box(page):
await page.setContent('<input id="checkbox" type="checkbox"></input>')
input = await page.querySelector('input')
await input.check()
assert await page.evaluate('checkbox.checked')

async def test_should_uncheck_the_box(page):
async def test_uncheck_the_box(page):
await page.setContent('<input id="checkbox" type="checkbox" checked></input>')
input = await page.querySelector('input')
await input.uncheck()
assert await page.evaluate('checkbox.checked') == False

async def test_should_select_single_option(page, server):
async def test_select_single_option(page, server):
await page.goto(server.PREFIX + '/input/select.html')
select = await page.querySelector('select')
await select.selectOption('blue')
assert await page.evaluate('result.onInput') == ['blue']
assert await page.evaluate('result.onChange') == ['blue']

async def test_should_focus_a_button(page, server):
async def test_focus_a_button(page, server):
await page.goto(server.PREFIX + '/input/button.html')
button = await page.querySelector('button')
assert await button.evaluate('button => document.activeElement === button') == False
Expand Down
2 changes: 1 addition & 1 deletion tests/test_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ async def test_frames_respect_name(page):
async def test_frames_respect_url(page, server):
await page.setContent(f'<iframe src="{server.EMPTY_PAGE}"></iframe>')
assert page.frame(url='bogus') is None
assert page.frame(url=f'**/empty.html').url == ('http://localhost:8907/empty.html')
assert page.frame(url=f'**/empty.html').url == (f'http://localhost:{server.PORT}/empty.html')