playwright-ruby-client 1.28.1 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/accessibility.md +9 -14
  3. data/documentation/docs/api/api_request_context.md +44 -41
  4. data/documentation/docs/api/api_response.md +13 -3
  5. data/documentation/docs/api/browser.md +24 -23
  6. data/documentation/docs/api/browser_context.md +71 -45
  7. data/documentation/docs/api/browser_type.md +21 -14
  8. data/documentation/docs/api/cdp_session.md +3 -5
  9. data/documentation/docs/api/console_message.md +7 -4
  10. data/documentation/docs/api/dialog.md +9 -5
  11. data/documentation/docs/api/download.md +19 -11
  12. data/documentation/docs/api/element_handle.md +125 -116
  13. data/documentation/docs/api/experimental/android.md +4 -5
  14. data/documentation/docs/api/experimental/android_device.md +11 -2
  15. data/documentation/docs/api/experimental/android_input.md +5 -0
  16. data/documentation/docs/api/file_chooser.md +6 -3
  17. data/documentation/docs/api/frame.md +182 -171
  18. data/documentation/docs/api/frame_locator.md +27 -38
  19. data/documentation/docs/api/js_handle.md +16 -10
  20. data/documentation/docs/api/keyboard.md +29 -16
  21. data/documentation/docs/api/locator.md +189 -140
  22. data/documentation/docs/api/mouse.md +9 -4
  23. data/documentation/docs/api/page.md +304 -289
  24. data/documentation/docs/api/playwright.md +8 -5
  25. data/documentation/docs/api/request.md +34 -15
  26. data/documentation/docs/api/response.md +27 -10
  27. data/documentation/docs/api/route.md +44 -12
  28. data/documentation/docs/api/selectors.md +5 -3
  29. data/documentation/docs/api/touchscreen.md +2 -0
  30. data/documentation/docs/api/tracing.md +11 -11
  31. data/documentation/docs/api/web_socket.md +9 -4
  32. data/documentation/docs/api/worker.md +12 -11
  33. data/documentation/docs/include/api_coverage.md +2 -0
  34. data/lib/playwright/channel_owners/api_request_context.rb +37 -2
  35. data/lib/playwright/channel_owners/browser_context.rb +22 -26
  36. data/lib/playwright/channel_owners/page.rb +35 -25
  37. data/lib/playwright/channel_owners/route.rb +28 -8
  38. data/lib/playwright/event_emitter.rb +6 -1
  39. data/lib/playwright/locator_impl.rb +8 -0
  40. data/lib/playwright/select_option_values.rb +2 -0
  41. data/lib/playwright/version.rb +2 -2
  42. data/lib/playwright_api/accessibility.rb +9 -13
  43. data/lib/playwright_api/android.rb +8 -6
  44. data/lib/playwright_api/android_device.rb +32 -7
  45. data/lib/playwright_api/android_input.rb +5 -0
  46. data/lib/playwright_api/android_socket.rb +4 -2
  47. data/lib/playwright_api/android_web_view.rb +5 -2
  48. data/lib/playwright_api/api_request.rb +6 -3
  49. data/lib/playwright_api/api_request_context.rb +46 -36
  50. data/lib/playwright_api/api_response.rb +13 -2
  51. data/lib/playwright_api/browser.rb +24 -16
  52. data/lib/playwright_api/browser_context.rb +76 -39
  53. data/lib/playwright_api/browser_type.rb +23 -13
  54. data/lib/playwright_api/cdp_session.rb +3 -4
  55. data/lib/playwright_api/console_message.rb +7 -2
  56. data/lib/playwright_api/dialog.rb +8 -4
  57. data/lib/playwright_api/download.rb +19 -9
  58. data/lib/playwright_api/element_handle.rb +116 -93
  59. data/lib/playwright_api/file_chooser.rb +6 -1
  60. data/lib/playwright_api/frame.rb +180 -135
  61. data/lib/playwright_api/frame_locator.rb +29 -32
  62. data/lib/playwright_api/js_handle.rb +16 -6
  63. data/lib/playwright_api/keyboard.rb +29 -14
  64. data/lib/playwright_api/locator.rb +183 -112
  65. data/lib/playwright_api/mouse.rb +9 -2
  66. data/lib/playwright_api/page.rb +301 -253
  67. data/lib/playwright_api/playwright.rb +11 -4
  68. data/lib/playwright_api/request.rb +34 -7
  69. data/lib/playwright_api/response.rb +27 -10
  70. data/lib/playwright_api/route.rb +44 -11
  71. data/lib/playwright_api/selectors.rb +6 -1
  72. data/lib/playwright_api/touchscreen.rb +2 -0
  73. data/lib/playwright_api/tracing.rb +11 -5
  74. data/lib/playwright_api/web_socket.rb +9 -4
  75. data/lib/playwright_api/worker.rb +16 -13
  76. data/playwright.gemspec +1 -1
  77. metadata +7 -7
@@ -1,7 +1,6 @@
1
1
  module Playwright
2
- # FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the `iframe`
3
- # and locate elements in that iframe. FrameLocator can be created with either [`method: Page.frameLocator`] or
4
- # [`method: Locator.frameLocator`] method.
2
+ #
3
+ # FrameLocator represents a view to the `iframe` on the page. It captures the logic sufficient to retrieve the `iframe` and locate elements in that iframe. FrameLocator can be created with either [`method: Page.frameLocator`] or [`method: Locator.frameLocator`] method.
5
4
  #
6
5
  # ```python sync
7
6
  # locator = page.frame_locator("my-frame").get_by_text("Submit")
@@ -10,8 +9,7 @@ module Playwright
10
9
  #
11
10
  # **Strictness**
12
11
  #
13
- # Frame locators are strict. This means that all operations on frame locators will throw if more than one element matches
14
- # a given selector.
12
+ # Frame locators are strict. This means that all operations on frame locators will throw if more than one element matches a given selector.
15
13
  #
16
14
  # ```python sync
17
15
  # # Throws if there are several frames in DOM:
@@ -23,25 +21,27 @@ module Playwright
23
21
  #
24
22
  # **Converting Locator to FrameLocator**
25
23
  #
26
- # If you have a `Locator` object pointing to an `iframe` it can be converted to `FrameLocator` using
27
- # [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope) CSS selector:
24
+ # If you have a `Locator` object pointing to an `iframe` it can be converted to `FrameLocator` using [`:scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/:scope) CSS selector:
28
25
  #
29
26
  # ```python sync
30
27
  # frameLocator = locator.frame_locator(":scope")
31
28
  # ```
32
29
  class FrameLocator < PlaywrightApi
33
30
 
31
+ #
34
32
  # Returns locator to the first matching frame.
35
33
  def first
36
34
  wrap_impl(@impl.first)
37
35
  end
38
36
 
39
- # When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements in
40
- # that iframe.
37
+ #
38
+ # When working with iframes, you can create a frame locator that will enter the iframe and allow selecting elements
39
+ # in that iframe.
41
40
  def frame_locator(selector)
42
41
  wrap_impl(@impl.frame_locator(unwrap_impl(selector)))
43
42
  end
44
43
 
44
+ #
45
45
  # Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
46
46
  #
47
47
  # ```html
@@ -51,8 +51,8 @@ module Playwright
51
51
  wrap_impl(@impl.get_by_alt_text(unwrap_impl(text), exact: unwrap_impl(exact)))
52
52
  end
53
53
 
54
- # Allows locating input elements by the text of the associated label. For example, this method will find the input by
55
- # label text "Password" in the following DOM:
54
+ #
55
+ # Allows locating input elements by the text of the associated label. For example, this method will find the input by label text "Password" in the following DOM:
56
56
  #
57
57
  # ```html
58
58
  # <label for="password-input">Password:</label>
@@ -62,8 +62,8 @@ module Playwright
62
62
  wrap_impl(@impl.get_by_label(unwrap_impl(text), exact: unwrap_impl(exact)))
63
63
  end
64
64
 
65
- # Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
66
- # "Country":
65
+ #
66
+ # Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder "Country":
67
67
  #
68
68
  # ```html
69
69
  # <input placeholder="Country">
@@ -72,15 +72,10 @@ module Playwright
72
72
  wrap_impl(@impl.get_by_placeholder(unwrap_impl(text), exact: unwrap_impl(exact)))
73
73
  end
74
74
 
75
- # Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
76
- # [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
77
- # [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace**
78
- # accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
79
- #
80
- # Note that many html elements have an implicitly
81
- # [defined role](https://w3c.github.io/html-aam/#html-element-role-mappings) that is recognized by the role selector. You
82
- # can find all the [supported roles here](https://www.w3.org/TR/wai-aria-1.2/#role_definitions). ARIA guidelines **do not
83
- # recommend** duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values.
75
+ #
76
+ # Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles), [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
77
+ #
78
+ # Note that many html elements have an implicitly [defined role](https://w3c.github.io/html-aam/#html-element-role-mappings) that is recognized by the role selector. You can find all the [supported roles here](https://www.w3.org/TR/wai-aria-1.2/#role_definitions). ARIA guidelines **do not recommend** duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values.
84
79
  def get_by_role(
85
80
  role,
86
81
  checked: nil,
@@ -95,12 +90,13 @@ module Playwright
95
90
  wrap_impl(@impl.get_by_role(unwrap_impl(role), checked: unwrap_impl(checked), disabled: unwrap_impl(disabled), exact: unwrap_impl(exact), expanded: unwrap_impl(expanded), includeHidden: unwrap_impl(includeHidden), level: unwrap_impl(level), name: unwrap_impl(name), pressed: unwrap_impl(pressed), selected: unwrap_impl(selected)))
96
91
  end
97
92
 
98
- # Locate element by the test id. By default, the `data-testid` attribute is used as a test id. Use
99
- # [`method: Selectors.setTestIdAttribute`] to configure a different test id attribute if necessary.
93
+ #
94
+ # Locate element by the test id. By default, the `data-testid` attribute is used as a test id. Use [`method: Selectors.setTestIdAttribute`] to configure a different test id attribute if necessary.
100
95
  def get_by_test_id(testId)
101
96
  wrap_impl(@impl.get_by_test_id(unwrap_impl(testId)))
102
97
  end
103
98
 
99
+ #
104
100
  # Allows locating elements that contain given text. Consider the following DOM structure:
105
101
  #
106
102
  # ```html
@@ -127,17 +123,16 @@ module Playwright
127
123
  # page.get_by_text(re.compile("^hello$", re.IGNORECASE))
128
124
  # ```
129
125
  #
130
- # See also [`method: Locator.filter`] that allows to match by another criteria, like an accessible role, and then filter
131
- # by the text content.
126
+ # See also [`method: Locator.filter`] that allows to match by another criteria, like an accessible role, and then filter by the text content.
132
127
  #
133
- # > NOTE: Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into
134
- # one, turns line breaks into spaces and ignores leading and trailing whitespace.
135
- # > NOTE: Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For
136
- # example, locating by text `"Log in"` matches `<input type=button value="Log in">`.
128
+ # **NOTE**: Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.
129
+ #
130
+ # **NOTE**: Input elements of the type `button` and `submit` are matched by their `value` instead of the text content. For example, locating by text `"Log in"` matches `<input type=button value="Log in">`.
137
131
  def get_by_text(text, exact: nil)
138
132
  wrap_impl(@impl.get_by_text(unwrap_impl(text), exact: unwrap_impl(exact)))
139
133
  end
140
134
 
135
+ #
141
136
  # Allows locating elements by their title. For example, this method will find the button by its title "Place the order":
142
137
  #
143
138
  # ```html
@@ -147,19 +142,21 @@ module Playwright
147
142
  wrap_impl(@impl.get_by_title(unwrap_impl(text), exact: unwrap_impl(exact)))
148
143
  end
149
144
 
145
+ #
150
146
  # Returns locator to the last matching frame.
151
147
  def last
152
148
  wrap_impl(@impl.last)
153
149
  end
154
150
 
155
- # The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options,
156
- # similar to [`method: Locator.filter`] method.
151
+ #
152
+ # The method finds an element matching the specified selector in the locator's subtree. It also accepts filter options, similar to [`method: Locator.filter`] method.
157
153
  #
158
154
  # [Learn more about locators](../locators.md).
159
155
  def locator(selector, has: nil, hasText: nil)
160
156
  wrap_impl(@impl.locator(unwrap_impl(selector), has: unwrap_impl(has), hasText: unwrap_impl(hasText)))
161
157
  end
162
158
 
159
+ #
163
160
  # Returns locator to the n-th matching frame. It's zero based, `nth(0)` selects the first frame.
164
161
  def nth(index)
165
162
  wrap_impl(@impl.nth(unwrap_impl(index)))
@@ -1,4 +1,5 @@
1
1
  module Playwright
2
+ #
2
3
  # JSHandle represents an in-page JavaScript object. JSHandles can be created with the [`method: Page.evaluateHandle`]
3
4
  # method.
4
5
  #
@@ -15,23 +16,27 @@ module Playwright
15
16
  # [`method: Page.evaluateHandle`] methods.
16
17
  class JSHandle < PlaywrightApi
17
18
 
19
+ #
18
20
  # Returns either `null` or the object handle itself, if the object handle is an instance of `ElementHandle`.
19
21
  def as_element
20
22
  wrap_impl(@impl.as_element)
21
23
  end
22
24
 
25
+ #
23
26
  # The `jsHandle.dispose` method stops referencing the element handle.
24
27
  def dispose
25
28
  wrap_impl(@impl.dispose)
26
29
  end
27
30
 
31
+ #
28
32
  # Returns the return value of `expression`.
29
33
  #
30
34
  # This method passes this handle as the first argument to `expression`.
31
35
  #
32
- # If `expression` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its value.
36
+ # If `expression` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return
37
+ # its value.
33
38
  #
34
- # Examples:
39
+ # **Usage**
35
40
  #
36
41
  # ```python sync
37
42
  # tweet_handle = page.query_selector(".tweet .retweets")
@@ -41,12 +46,12 @@ module Playwright
41
46
  wrap_impl(@impl.evaluate(unwrap_impl(expression), arg: unwrap_impl(arg)))
42
47
  end
43
48
 
49
+ #
44
50
  # Returns the return value of `expression` as a `JSHandle`.
45
51
  #
46
52
  # This method passes this handle as the first argument to `expression`.
47
53
  #
48
- # The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns
49
- # `JSHandle`.
54
+ # The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns `JSHandle`.
50
55
  #
51
56
  # If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would wait
52
57
  # for the promise to resolve and return its value.
@@ -56,8 +61,11 @@ module Playwright
56
61
  wrap_impl(@impl.evaluate_handle(unwrap_impl(expression), arg: unwrap_impl(arg)))
57
62
  end
58
63
 
64
+ #
59
65
  # The method returns a map with **own property names** as keys and JSHandle instances for the property values.
60
66
  #
67
+ # **Usage**
68
+ #
61
69
  # ```python sync
62
70
  # handle = page.evaluate_handle("({window, document})")
63
71
  # properties = handle.get_properties()
@@ -70,15 +78,17 @@ module Playwright
70
78
  end
71
79
  alias_method :properties, :get_properties
72
80
 
81
+ #
73
82
  # Fetches a single property from the referenced object.
74
83
  def get_property(propertyName)
75
84
  wrap_impl(@impl.get_property(unwrap_impl(propertyName)))
76
85
  end
77
86
 
87
+ #
78
88
  # Returns a JSON representation of the object. If the object has a `toJSON` function, it **will not be called**.
79
89
  #
80
- # > NOTE: The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an
81
- # error if the object has circular references.
90
+ # **NOTE**: The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an error if the
91
+ # object has circular references.
82
92
  def json_value
83
93
  wrap_impl(@impl.json_value)
84
94
  end
@@ -1,4 +1,5 @@
1
1
  module Playwright
2
+ #
2
3
  # Keyboard provides an api for managing a virtual keyboard. The high level api is [`method: Keyboard.type`], which takes
3
4
  # raw characters and generates proper `keydown`, `keypress`/`input`, and `keyup` events on your page.
4
5
  #
@@ -36,10 +37,12 @@ module Playwright
36
37
  # ```
37
38
  class Keyboard < PlaywrightApi
38
39
 
40
+ #
39
41
  # Dispatches a `keydown` event.
40
42
  #
41
- # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
42
- # value or a single character to generate the text for. A superset of the `key` values can be found
43
+ # `key` can specify the intended
44
+ # [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to
45
+ # generate the text for. A superset of the `key` values can be found
43
46
  # [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
44
47
  #
45
48
  # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
@@ -49,34 +52,39 @@ module Playwright
49
52
  #
50
53
  # Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
51
54
  #
52
- # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
53
- # texts.
55
+ # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different
56
+ # respective texts.
54
57
  #
55
- # If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, subsequent key presses will be sent with that modifier
56
- # active. To release the modifier key, use [`method: Keyboard.up`].
58
+ # If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, subsequent key presses will be sent with that
59
+ # modifier active. To release the modifier key, use [`method: Keyboard.up`].
57
60
  #
58
61
  # After the key is pressed once, subsequent calls to [`method: Keyboard.down`] will have
59
62
  # [repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat) set to true. To release the key, use
60
63
  # [`method: Keyboard.up`].
61
64
  #
62
- # > NOTE: Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
65
+ # **NOTE**: Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
63
66
  def down(key)
64
67
  wrap_impl(@impl.down(unwrap_impl(key)))
65
68
  end
66
69
 
70
+ #
67
71
  # Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
68
72
  #
73
+ # **Usage**
74
+ #
69
75
  # ```python sync
70
76
  # page.keyboard.insert_text("嗨")
71
77
  # ```
72
78
  #
73
- # > NOTE: Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
79
+ # **NOTE**: Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
74
80
  def insert_text(text)
75
81
  wrap_impl(@impl.insert_text(unwrap_impl(text)))
76
82
  end
77
83
 
78
- # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
79
- # value or a single character to generate the text for. A superset of the `key` values can be found
84
+ #
85
+ # `key` can specify the intended
86
+ # [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to
87
+ # generate the text for. A superset of the `key` values can be found
80
88
  # [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
81
89
  #
82
90
  # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
@@ -86,12 +94,14 @@ module Playwright
86
94
  #
87
95
  # Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
88
96
  #
89
- # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
90
- # texts.
97
+ # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different
98
+ # respective texts.
91
99
  #
92
100
  # Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When specified with the
93
101
  # modifier, modifier is pressed and being held while the subsequent key is being pressed.
94
102
  #
103
+ # **Usage**
104
+ #
95
105
  # ```python sync
96
106
  # page = browser.new_page()
97
107
  # page.goto("https://keycode.info")
@@ -109,21 +119,26 @@ module Playwright
109
119
  wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay)))
110
120
  end
111
121
 
122
+ #
112
123
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
113
124
  #
114
125
  # To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.press`].
115
126
  #
127
+ # **Usage**
128
+ #
116
129
  # ```python sync
117
130
  # page.keyboard.type("Hello") # types instantly
118
131
  # page.keyboard.type("World", delay=100) # types slower, like a user
119
132
  # ```
120
133
  #
121
- # > NOTE: Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
122
- # > NOTE: For characters that are not on a US keyboard, only an `input` event will be sent.
134
+ # **NOTE**: Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
135
+ #
136
+ # **NOTE**: For characters that are not on a US keyboard, only an `input` event will be sent.
123
137
  def type(text, delay: nil)
124
138
  wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay)))
125
139
  end
126
140
 
141
+ #
127
142
  # Dispatches a `keyup` event.
128
143
  def up(key)
129
144
  wrap_impl(@impl.up(unwrap_impl(key)))