Skip to content

Commit 0e136ae

Browse files
committed
more tests
1 parent 5d322d4 commit 0e136ae

File tree

5 files changed

+136
-7
lines changed

5 files changed

+136
-7
lines changed

playwright/_impl/_connection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _dispose(self) -> None:
141141

142142
class ProtocolCallback:
143143
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
144-
self.stack_trace: traceback.StackSummary = traceback.StackSummary()
144+
self.stack_trace: traceback.StackSummary
145145
self.future = loop.create_future()
146146
# The outer task can get cancelled by the user, this forwards the cancellation to the inner task.
147147
current_task = asyncio.current_task()
@@ -252,10 +252,10 @@ def _send_message_to_server(
252252
id = self._last_id
253253
callback = ProtocolCallback(self._loop)
254254
task = asyncio.current_task(self._loop)
255-
stack_trace: Optional[traceback.StackSummary] = getattr(
256-
task, "__pw_stack_trace__", None
255+
callback.stack_trace = cast(
256+
traceback.StackSummary,
257+
getattr(task, "__pw_stack_trace__", traceback.extract_stack()),
257258
)
258-
callback.stack_trace = stack_trace or traceback.extract_stack()
259259
self._callbacks[id] = callback
260260
message = {
261261
"id": id,

playwright/_impl/_sync_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import asyncio
1616
import inspect
17+
import traceback
1718
from types import TracebackType
1819
from typing import Any, Awaitable, Callable, Dict, Generic, List, Type, TypeVar, cast
1920

@@ -79,6 +80,7 @@ def _sync(self, coro: Awaitable) -> Any:
7980
g_self = greenlet.getcurrent()
8081
task = self._loop.create_task(coro)
8182
setattr(task, "__pw_stack__", inspect.stack())
83+
setattr(task, "__pw_stack_trace__", traceback.extract_stack())
8284

8385
task.add_done_callback(lambda _: g_self.switch())
8486
while not task.done():

tests/async/test_tracing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ async def test_should_collect_trace_with_resources_but_no_js(
103103
assert events_have_entry(events, "Keyboard.insert_text") is True
104104
assert events_have_entry(events, "Page.close") is True
105105

106-
assert len(list(filter(lambda e: e["type"] == "frame-snapshot", events))) > 1
107-
assert len(list(filter(lambda e: e["type"] == "screencast-frame", events))) > 1
106+
assert len(list(filter(lambda e: e["type"] == "frame-snapshot", events))) >= 1
107+
assert len(list(filter(lambda e: e["type"] == "screencast-frame", events))) >= 1
108108
style = list(
109109
filter(
110110
lambda e: e["type"] == "resource-snapshot"

tests/sync/test_page.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from playwright.sync_api import Page
15+
import pytest
16+
17+
from playwright.sync_api import Error, Page
1618
from tests.server import Server
1719

1820

@@ -66,3 +68,11 @@ def test_should_set_bodysize_to_0(page: Page, server: Server) -> None:
6668
sizes = request.sizes()
6769
assert sizes["requestBodySize"] == 0
6870
assert sizes["requestHeadersSize"] >= 200
71+
72+
73+
def test_sync_stacks_should_work(page: Page, server: Server) -> None:
74+
page.route("**/empty.html", lambda route: route.abort())
75+
with pytest.raises(Error) as exc_info:
76+
page.goto(server.EMPTY_PAGE)
77+
assert exc_info.value.stack
78+
assert __file__ in exc_info.value.stack

tests/sync/test_tracing.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,119 @@ def test_should_collect_sources(
7878
assert found_current_file
7979

8080

81+
def test_should_collect_trace_with_resources_but_no_js(
82+
context: BrowserContext, page: Page, server: Server, tmpdir: Path
83+
) -> None:
84+
context.tracing.start(screenshots=True, snapshots=True)
85+
page.goto(server.PREFIX + "/frames/frame.html")
86+
page.set_content("<button>Click</button>")
87+
page.click('"Click"')
88+
page.mouse.move(20, 20)
89+
page.mouse.dblclick(30, 30)
90+
page.keyboard.insert_text("abc")
91+
page.wait_for_timeout(2000) # Give it some time to produce screenshots.
92+
page.close()
93+
trace_file_path = tmpdir / "trace.zip"
94+
context.tracing.stop(path=trace_file_path)
95+
96+
(_, events) = parse_trace(trace_file_path)
97+
assert events[0]["type"] == "context-options"
98+
assert events_have_entry(events, "Page.goto") is True
99+
assert events_have_entry(events, "Page.set_content") is True
100+
assert events_have_entry(events, "Page.click") is True
101+
assert events_have_entry(events, "Mouse.move") is True
102+
assert events_have_entry(events, "Mouse.dblclick") is True
103+
assert events_have_entry(events, "Keyboard.insert_text") is True
104+
assert events_have_entry(events, "Page.close") is True
105+
106+
assert len(list(filter(lambda e: e["type"] == "frame-snapshot", events))) >= 1
107+
assert len(list(filter(lambda e: e["type"] == "screencast-frame", events))) >= 1
108+
style = list(
109+
filter(
110+
lambda e: e["type"] == "resource-snapshot"
111+
and e["snapshot"]["request"]["url"].endswith("style.css"),
112+
events,
113+
)
114+
)[0]
115+
assert style
116+
assert style["snapshot"]["response"]["content"]["_sha1"]
117+
script = list(
118+
filter(
119+
lambda e: e["type"] == "resource-snapshot"
120+
and e["snapshot"]["request"]["url"].endswith("script.js"),
121+
events,
122+
)
123+
)[0]
124+
assert script
125+
assert script["snapshot"]["response"]["content"].get("_sha1") is None
126+
127+
128+
def test_should_collect_two_traces(
129+
context: BrowserContext, page: Page, server: Server, tmpdir: Path
130+
) -> None:
131+
context.tracing.start(screenshots=True, snapshots=True)
132+
page.goto(server.EMPTY_PAGE)
133+
page.set_content("<button>Click</button>")
134+
page.click('"Click"')
135+
tracing1_path = tmpdir / "trace1.zip"
136+
context.tracing.stop(path=tracing1_path)
137+
138+
context.tracing.start(screenshots=True, snapshots=True)
139+
page.dblclick('"Click"')
140+
page.close()
141+
tracing2_path = tmpdir / "trace2.zip"
142+
context.tracing.stop(path=tracing2_path)
143+
144+
(_, events) = parse_trace(tracing1_path)
145+
assert events[0]["type"] == "context-options"
146+
assert events_have_entry(events, "Page.goto") is True
147+
assert events_have_entry(events, "Page.set_content") is True
148+
assert events_have_entry(events, "Page.click") is True
149+
assert events_have_entry(events, "Page.dblclick") is False
150+
assert events_have_entry(events, "Page.close") is False
151+
152+
(_, events) = parse_trace(tracing2_path)
153+
assert events[0]["type"] == "context-options"
154+
assert events_have_entry(events, "Page.goto") is False
155+
assert events_have_entry(events, "Page.set_content") is False
156+
assert events_have_entry(events, "Page.click") is False
157+
assert events_have_entry(events, "Page.dblclick") is True
158+
assert events_have_entry(events, "Page.close") is True
159+
160+
161+
def test_should_not_throw_when_stopping_without_start_but_not_exporting(
162+
context: BrowserContext,
163+
) -> None:
164+
context.tracing.stop()
165+
166+
167+
def test_should_work_with_playwright_context_managers(
168+
context: BrowserContext, page: Page, server: Server, tmpdir: Path
169+
) -> None:
170+
context.tracing.start(screenshots=True, snapshots=True)
171+
page.goto(server.EMPTY_PAGE)
172+
page.set_content("<button>Click</button>")
173+
with page.expect_console_message() as message_info:
174+
page.evaluate('() => console.log("hello")')
175+
page.click('"Click"')
176+
assert (message_info.value).text == "hello"
177+
178+
with page.expect_popup():
179+
page.evaluate("window._popup = window.open(document.location.href)")
180+
trace_file_path = tmpdir / "trace.zip"
181+
context.tracing.stop(path=trace_file_path)
182+
183+
(_, events) = parse_trace(trace_file_path)
184+
assert events[0]["type"] == "context-options"
185+
assert events_have_entry(events, "Page.goto")
186+
assert events_have_entry(events, "Page.set_content")
187+
assert events_have_entry(events, "Page.expect_console_message")
188+
assert events_have_entry(events, "Page.evaluate")
189+
assert events_have_entry(events, "Page.click")
190+
assert events_have_entry(events, "Page.expect_popup")
191+
assert events_have_entry(events, "Page.evaluate")
192+
193+
81194
def parse_trace(path: Path) -> Tuple[Dict[str, bytes], List[Any]]:
82195
resources: Dict[str, bytes] = {}
83196
with zipfile.ZipFile(path, "r") as zip:
@@ -88,3 +201,7 @@ def parse_trace(path: Path) -> Tuple[Dict[str, bytes], List[Any]]:
88201
for line in resources[name].decode().splitlines():
89202
events.append(json.loads(line))
90203
return (resources, events)
204+
205+
206+
def events_have_entry(events: List[Any], api_name: str) -> bool:
207+
return any(e.get("metadata", {}).get("apiName") == api_name for e in events)

0 commit comments

Comments
 (0)