feat: add autofill support (#10565)
This commit is contained in:
parent
c14f9b64a7
commit
6c9306a72e
@ -67,6 +67,7 @@ sidebar_label: API
|
||||
| Interface | Description |
|
||||
| --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [ActionOptions](./puppeteer.actionoptions.md) | |
|
||||
| [AutofillData](./puppeteer.autofilldata.md) | |
|
||||
| [BoundingBox](./puppeteer.boundingbox.md) | |
|
||||
| [BoxModel](./puppeteer.boxmodel.md) | |
|
||||
| [BrowserConnectOptions](./puppeteer.browserconnectoptions.md) | Generic browser options that can be passed when launching any browser or when connecting to an existing browser instance. |
|
||||
|
17
docs/api/puppeteer.autofilldata.md
Normal file
17
docs/api/puppeteer.autofilldata.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
sidebar_label: AutofillData
|
||||
---
|
||||
|
||||
# AutofillData interface
|
||||
|
||||
#### Signature:
|
||||
|
||||
```typescript
|
||||
export interface AutofillData
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description | Default |
|
||||
| ---------- | --------- | --------------------------------------------------------------------------------------- | ----------- | ------- |
|
||||
| creditCard | | { number: string; name: string; expiryMonth: string; expiryYear: string; cvc: string; } | | |
|
44
docs/api/puppeteer.elementhandle.autofill.md
Normal file
44
docs/api/puppeteer.elementhandle.autofill.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
sidebar_label: ElementHandle.autofill
|
||||
---
|
||||
|
||||
# ElementHandle.autofill() method
|
||||
|
||||
If the element is a form input, you can use [ElementHandle.autofill()](./puppeteer.elementhandle.autofill.md) to test if the form is compatible with the browser's autofill implementation. Throws an error if the form cannot be autofilled.
|
||||
|
||||
#### Signature:
|
||||
|
||||
```typescript
|
||||
class ElementHandle {
|
||||
autofill(data: AutofillData): Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ------------------------------------------- | ----------- |
|
||||
| data | [AutofillData](./puppeteer.autofilldata.md) | |
|
||||
|
||||
**Returns:**
|
||||
|
||||
Promise<void>
|
||||
|
||||
## Remarks
|
||||
|
||||
Currently, Puppeteer supports auto-filling credit card information only and in Chrome in the new headless and headful modes only.
|
||||
|
||||
```ts
|
||||
// Select an input on the credit card form.
|
||||
const name = await page.waitForSelector('form #name');
|
||||
// Trigger autofill with the desired data.
|
||||
await name.autofill({
|
||||
creditCard: {
|
||||
number: '4444444444444444',
|
||||
name: 'John Smith',
|
||||
expiryMonth: '01',
|
||||
expiryYear: '2030',
|
||||
cvc: '123',
|
||||
},
|
||||
});
|
||||
```
|
@ -55,6 +55,7 @@ The constructor for this class is marked as internal. Third-party code should no
|
||||
| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | | <p>Runs the given function on the first element matching the given selector in the current element.</p><p>If the given function returns a promise, then this method will wait till the promise resolves.</p> |
|
||||
| [$x(expression)](./puppeteer.elementhandle._x.md) | | |
|
||||
| [asElement()](./puppeteer.elementhandle.aselement.md) | | |
|
||||
| [autofill(data)](./puppeteer.elementhandle.autofill.md) | | If the element is a form input, you can use [ElementHandle.autofill()](./puppeteer.elementhandle.autofill.md) to test if the form is compatible with the browser's autofill implementation. Throws an error if the form cannot be autofilled. |
|
||||
| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or <code>null</code> if the element is not visible. |
|
||||
| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or <code>null</code> if the element is not visible. |
|
||||
| [click(this, options)](./puppeteer.elementhandle.click.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.md) to click in the center of the element. If the element is detached from DOM, the method throws an error. |
|
||||
|
@ -1042,4 +1042,45 @@ export class ElementHandle<
|
||||
assertElementHasWorld(): asserts this {
|
||||
assert(this.executionContext()._world);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the element is a form input, you can use {@link ElementHandle.autofill}
|
||||
* to test if the form is compatible with the browser's autofill
|
||||
* implementation. Throws an error if the form cannot be autofilled.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Currently, Puppeteer supports auto-filling credit card information only and
|
||||
* in Chrome in the new headless and headful modes only.
|
||||
*
|
||||
* ```ts
|
||||
* // Select an input on the credit card form.
|
||||
* const name = await page.waitForSelector('form #name');
|
||||
* // Trigger autofill with the desired data.
|
||||
* await name.autofill({
|
||||
* creditCard: {
|
||||
* number: '4444444444444444',
|
||||
* name: 'John Smith',
|
||||
* expiryMonth: '01',
|
||||
* expiryYear: '2030',
|
||||
* cvc: '123',
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
autofill(data: AutofillData): Promise<void>;
|
||||
autofill(): Promise<void> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export interface AutofillData {
|
||||
creditCard: {
|
||||
// See https://chromedevtools.github.io/devtools-protocol/tot/Autofill/#type-CreditCard.
|
||||
number: string;
|
||||
name: string;
|
||||
expiryMonth: string;
|
||||
expiryYear: string;
|
||||
cvc: string;
|
||||
};
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
import {Protocol} from 'devtools-protocol';
|
||||
|
||||
import {
|
||||
AutofillData,
|
||||
BoundingBox,
|
||||
BoxModel,
|
||||
ClickOptions,
|
||||
@ -571,6 +572,19 @@ export class CDPElementHandle<
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
override async autofill(data: AutofillData): Promise<void> {
|
||||
const nodeInfo = await this.client.send('DOM.describeNode', {
|
||||
objectId: this.handle.id,
|
||||
});
|
||||
const fieldId = nodeInfo.node.backendNodeId;
|
||||
const frameId = this.#frame._id;
|
||||
await this.client.send('Autofill.trigger', {
|
||||
fieldId,
|
||||
frameId,
|
||||
card: data.creditCard,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function computeQuadArea(quad: Point[]): number {
|
||||
|
@ -17,6 +17,7 @@
|
||||
import * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
|
||||
|
||||
import {
|
||||
AutofillData,
|
||||
ElementHandle as BaseElementHandle,
|
||||
ClickOptions,
|
||||
} from '../../api/ElementHandle.js';
|
||||
@ -70,6 +71,20 @@ export class ElementHandle<
|
||||
return;
|
||||
}
|
||||
|
||||
override async autofill(data: AutofillData): Promise<void> {
|
||||
const client = this.#frame.context().cdpSession;
|
||||
const nodeInfo = await client.send('DOM.describeNode', {
|
||||
objectId: this.handle.id,
|
||||
});
|
||||
const fieldId = nodeInfo.node.backendNodeId;
|
||||
const frameId = this.#frame._id;
|
||||
await client.send('Autofill.trigger', {
|
||||
fieldId,
|
||||
frameId,
|
||||
card: data.creditCard,
|
||||
});
|
||||
}
|
||||
|
||||
// ///////////////////
|
||||
// // Input methods //
|
||||
// ///////////////////
|
||||
|
@ -5,6 +5,18 @@
|
||||
"parameters": ["webDriverBiDi"],
|
||||
"expectations": ["SKIP", "TIMEOUT"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[autofill.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["chrome"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[autofill.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["firefox"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[chromiumonly.spec] Chromium-Specific Launcher tests *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
@ -299,6 +311,12 @@
|
||||
"parameters": ["webDriverBiDi"],
|
||||
"expectations": ["PASS"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[autofill.spec] *",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
"parameters": ["chrome", "headless"],
|
||||
"expectations": ["FAIL"]
|
||||
},
|
||||
{
|
||||
"testIdPattern": "[browser.spec] Browser specs Browser.isConnected should set the browser connected state",
|
||||
"platforms": ["darwin", "linux", "win32"],
|
||||
|
42
test/assets/credit-card.html
Normal file
42
test/assets/credit-card.html
Normal file
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form id="testform" method="post">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="name">Name on Card</label>
|
||||
</td>
|
||||
<td>
|
||||
<input size="40" id="name" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label for="number">Card Number</label>
|
||||
</td>
|
||||
<td>
|
||||
<input size="40" id="number" name="card_number" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label>Expiration Date</label>
|
||||
</td>
|
||||
<td>
|
||||
<input size="2" id="expiration_month" name="ccmonth"> <input size="4" id="expiration_year"
|
||||
name="ccyear" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
48
test/src/autofill.spec.ts
Normal file
48
test/src/autofill.spec.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright 2023 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import expect from 'expect';
|
||||
|
||||
import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
|
||||
|
||||
describe('Autofill', function () {
|
||||
setupTestBrowserHooks();
|
||||
describe('ElementHandle.autofill', () => {
|
||||
it('should fill out a credit card', async () => {
|
||||
const {page, server} = await getTestState();
|
||||
await page.goto(server.PREFIX + '/credit-card.html');
|
||||
const name = await page.waitForSelector('#name');
|
||||
await name!.autofill({
|
||||
creditCard: {
|
||||
number: '4444444444444444',
|
||||
name: 'John Smith',
|
||||
expiryMonth: '01',
|
||||
expiryYear: '2030',
|
||||
cvc: '123',
|
||||
},
|
||||
});
|
||||
expect(
|
||||
await page.evaluate(() => {
|
||||
const result = [];
|
||||
for (const el of document.querySelectorAll('input')) {
|
||||
result.push(el.value);
|
||||
}
|
||||
return result.join(',');
|
||||
})
|
||||
).toBe('John Smith,4444444444444444,01,2030,Submit');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user