Skip to content

Commit 26d99d4

Browse files
committed
Example using a function rather than a Camera. Progress on facets.mdx.
1 parent cf5c255 commit 26d99d4

File tree

2 files changed

+39
-24
lines changed

2 files changed

+39
-24
lines changed

python/example-pytest-selfie/tests/selfie_settings.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
}
1010

1111

12-
def web_camera(response: TestResponse) -> Snapshot:
12+
def _web_camera(response: TestResponse) -> Snapshot:
1313
redirect_reason = REDIRECTS.get(response.status_code)
1414
if redirect_reason is not None:
1515
return Snapshot.of(
@@ -20,8 +20,8 @@ def web_camera(response: TestResponse) -> Snapshot:
2020
return Snapshot.of(response.data.decode()).plus_facet("status", response.status)
2121

2222

23-
WEB_CAMERA = Camera.of(web_camera)
23+
WEB_CAMERA = Camera.of(_web_camera)
2424

2525

2626
def web_selfie(response: TestResponse) -> StringSelfie:
27-
return expect_selfie(response, WEB_CAMERA)
27+
return expect_selfie(response, _web_camera)

selfie.dev/src/pages/py/facets.mdx

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,41 +114,56 @@ def web_selfie(response: TestResponse) -> StringSelfie:
114114

115115
So a snapshot doesn't have to be only one value, and it's fine if the schema changes depending on the content of the value being snapshotted. The snapshots are for you to read (and look at diffs of), so record whatever is meaningful to you.
116116

117+
## Cameras
118+
119+
So if you want to capture multiple facets of something, you need a function which turns that something into a `Snapshot`. Selfie calls this idea a `Camera`. You can pass a `Camera` as the second argument to `expect_selfie`, which would look like so:
120+
121+
```python
122+
def _web_camera(response: TestResponse) -> Snapshot:
123+
redirect_reason = REDIRECTS.get(response.status_code)
124+
if redirect_reason is not None:
125+
return Snapshot.of(
126+
f"REDIRECT {response.status_code} {redirect_reason} to "
127+
+ response.headers.get("Location", "<unknown>")
128+
)
129+
else:
130+
return Snapshot.of(response.data.decode()).plus_facet("status", response.status)
131+
132+
def web_selfie(response: TestResponse) -> StringSelfie:
133+
return expect_selfie(response, _web_camera)
134+
```
135+
117136
## Lenses
118137

119138
A `Lens` is a function that transforms one `Snapshot` into another `Snapshot`, transforming / creating / removing values along the way. For example, we might want to pretty-print the HTML in our snapshots.
120139

121140
```python
122141
from bs4 import BeautifulSoup
123142

124-
def pretty_print_html(html):
125-
soup = BeautifulSoup(html, 'html.parser')
126-
return soup.prettify()
127-
128-
def response_camera(response):
129-
(...)
130-
// call prettyPrint when we take the snapshot
131-
return Snapshot.of(pretty_print_html(response.body))
132-
.plus_facet("statusLine", response.status_line)
133-
143+
def _pretty_print_html(html : str) -> str:
144+
return BeautifulSoup(html, 'html.parser').prettify()
134145
```
135146

136-
Calling transformation functions inside the `Camera` is fine, but another option is to create a `Lens` and then use `Camera.withLens`. This approach is especially helpful if there are multiple `Camera`s which need the same transformation.
137-
138-
**TODO: [Not implemented](https://github.com/diffplug/selfie/issues/323)**
147+
One option is to call this function inside the `Camera`. But this mixes concerns - its better to have one function that grabs all the data (the `Camera`), and other functions that clean it up (the `Lens`es). Selfie makes it easy to combine these like so:
139148

140149
```python
141-
def pretty_print(snapshot):
142-
subject = snapshot.subject.value_string()
143-
if "<html>" in subject:
144-
return snapshot.plus_or_replace("", pretty_print_html(subject))
145-
else:
146-
return snapshot
150+
def _web_camera(response: TestResponse) -> Snapshot: ...
151+
def _pretty_print_html(html : str) -> str: ...
152+
def _pretty_print_lens(snapshot : Snapshot) -> Snapshot:
153+
if (snapshot.subject.contains("<html"))
154+
return snapshot.with_subject(_pretty_print_html(snapshot.subject))
155+
else
156+
return snapshot
157+
158+
_WEB_CAMERA = Camera.of(_web_camera).with_lens(_pretty_print_lens)
147159

148-
def expect_selfie(data: Union[Response, Email], camera):
149-
return Selfie.expect_selfie(data, camera.with_lens(pretty_print))
160+
def web_selfie(response: TestResponse) -> StringSelfie:
161+
return expect_selfie(response, _WEB_CAMERA)
150162
```
151163

164+
Calling transformation functions inside the `Camera` is fine, but another option is to create a `Lens` and then use `Camera.withLens`. This approach is especially helpful if there are multiple `Camera`s which need the same transformation.
165+
166+
152167
## Compound lens
153168

154169
Selfie has a useful class called [`CompoundLens`](https://github.com/diffplug/selfie/issues/324). It is a fluent API for mutating facets and piping data through functions from one facet into another. An important gotcha here is that the **subject** can be treated as a facet named `""` (empty string). `CompoundLens` uses this hack to simplify a snapshot into only a map of facets, instead of a subject plus a map of facets.

0 commit comments

Comments
 (0)