зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1740001 - Add cc exp year transformer, send input and change events when resetting select element via clear form. r=dimi,sgalich
Differential Revision: https://phabricator.services.mozilla.com/D139026
This commit is contained in:
Родитель
6ae637e5d7
Коммит
990afe241f
|
@ -590,7 +590,7 @@ add_task(function setup() {
|
|||
OSKeyStoreTestUtils.setup();
|
||||
});
|
||||
|
||||
registerCleanupFunction(removeAllRecords);
|
||||
registerCleanupFunction(async () => {
|
||||
await removeAllRecords();
|
||||
await OSKeyStoreTestUtils.cleanup();
|
||||
});
|
||||
|
|
90
browser/extensions/formautofill/test/fixtures/third_party/DirectAsda/Payment.html
поставляемый
Normal file
90
browser/extensions/formautofill/test/fixtures/third_party/DirectAsda/Payment.html
поставляемый
Normal file
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Direct.asda.com</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form class="card-form">
|
||||
<div class="form-group"><label class="label" for="cardNumber">Card number</label>
|
||||
<div>
|
||||
<div class="input-group"><input class="form-control error" name="cardNumber" type="tel" autocomplete="on"
|
||||
data-id="input-payment-add-card-number" value=""></div><span data-id="input-payment-add-card-number"
|
||||
class="error">Please enter a card number</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group"><label class="label" for="cardHolder">Name on card</label>
|
||||
<div>
|
||||
<div class="input-group"><input class="form-control" name="cardHolder" type="text" autocomplete="on"
|
||||
data-id="input-payment-add-card-name-on-card" value=""></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid__list card-grid">
|
||||
<div class="form-group cvv-form-group"><label class="label" for="cvv">CVV number</label>
|
||||
<div>
|
||||
<div class="input-group flex-grid flex-grid--center"><input class="form-control" name="cvv" type="tel"
|
||||
autocomplete="on" data-id="input-payment-add-card-cvv" value=""><span class="icon cvv-code-icon"><svg
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="36" height="24">
|
||||
<defs>
|
||||
<rect id="cvv-dep-a" width="36" height="24" rx="2.182"></rect>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<rect width="36" height="24" fill="#D8D8D8" fill-rule="nonzero" rx="2.182"></rect>
|
||||
<mask id="cvv-dep-b" fill="#fff">
|
||||
<use xlink:href="#cvv-dep-a"></use>
|
||||
</mask>
|
||||
<path fill="#191919" fill-rule="nonzero" d="M0 0h36v5.526H0z" mask="url(#cvv-dep-b)"></path>
|
||||
<rect width="6.545" height="4.435" x="26.727" y="9.282" stroke="#D8365A" stroke-width="1.091"
|
||||
rx=".545"></rect>
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M2.182 8.737H24v5.526H2.182z"></path>
|
||||
</g>
|
||||
</svg></span><span class="icon cvv-code-helper"><svg xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle fill="#191919" cx="12" cy="12" r="12"></circle><text font-family="Arial-BoldMT, Arial"
|
||||
font-size="15" font-weight="bold" fill="#FFF">
|
||||
<tspan x="7" y="17.235">?</tspan>
|
||||
</text>
|
||||
</g>
|
||||
</svg></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid__list adjust-date"><label class="label">Expiry date</label>
|
||||
<div>
|
||||
<div class="flex-grid--inline">
|
||||
<div class="flex-grid--inline">
|
||||
<div class="form-group expiry-month">
|
||||
<div>
|
||||
<div class="input-group"><input class="form-control" name="month" type="tel" placeholder="MM"
|
||||
data-id="input-payment-add-card-expiry-month" value=""></div>
|
||||
</div>
|
||||
</div><span class="date-separator">/</span>
|
||||
<div class="form-group expiry-year">
|
||||
<div class="input-group">
|
||||
<div>
|
||||
<div class="input-group"><input class="form-control" name="year" type="tel" placeholder="YY"
|
||||
data-id="input-payment-add-card-expiry-year" value=""></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="save-card-text">
|
||||
<div>
|
||||
<div class="checkbox-section size-normal"><input class="checkbox-field" name="save" id="save"
|
||||
data-id="checkbox-payment-save-card" type="checkbox"><label for="save"
|
||||
class="custom-checkbox"></label><label for="save" class="checkbox-label">Save card</label></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
154
browser/extensions/formautofill/test/fixtures/third_party/GlobalDirectAsda/Payment.html
поставляемый
Normal file
154
browser/extensions/formautofill/test/fixtures/third_party/GlobalDirectAsda/Payment.html
поставляемый
Normal file
|
@ -0,0 +1,154 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Global.direct.asda.com</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form action="/1/Payments/HandleCreditCardRequestV2?mode=13534" method="post" id="paymentFrm" novalidate="novalidate">
|
||||
<div class="clearfix" id="secureContainer" data-culture="en-GB" data-direction="ltr">
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group has-error has-feedback">
|
||||
|
||||
<label for="cardNum" class="col-sm-4 col-xs-12 control-label fcap paylabel">Card number<div data-show="true"
|
||||
class="glyphicon glyphicon-star astrsk"></div></label>
|
||||
<div class="col-sm-8 col-xs-12 fval" id="CreditCardCell" data-cc-valid="false">
|
||||
<input aria-label="Card number" autocomplete="off" class="form-control input-validation-error"
|
||||
data-type="unknown" data-type-id="1" data-val="true" data-val-luhn="Card number not valid"
|
||||
data-val-luhn-allowempty="False" data-val-luhn-allowspaces="False" data-val-required="Card number"
|
||||
id="cardNum" name="PaymentData.cardNum" pattern="[0-9]{13,16}" placeholder="Card number" type="tel"
|
||||
value="" aria-required="true"><span class="glyphicon glyphicon-remove form-control-feedback"
|
||||
aria-hidden="true"></span>
|
||||
<div id="cardTypeInfo">
|
||||
<div class="isvisa pm_visa pm_general"></div>
|
||||
<div class="ismastercard pm_mastercard pm_general"></div>
|
||||
<div class="isamex pm_amex pm_general"></div>
|
||||
<div class="ismaestro pm_maestro pm_general"></div>
|
||||
<div class="isjcb pm_jcb pm_general"></div>
|
||||
<div class="isdiners pm_diners pm_general"></div>
|
||||
<div class="isdiscover pm_discover pm_general"></div>
|
||||
<div class="ismir pm_mir pm_general"></div>
|
||||
<div class="isdefault pm_default pm_general"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cardExpiryMonth" class="col-sm-4 col-xs-12 control-label fcap paylabel">Expiry date<div
|
||||
data-show="true" class="glyphicon glyphicon-star astrsk"></div></label>
|
||||
<div class="col-sm-8 col-xs-12 fval">
|
||||
<div class="row" id="expDateRow">
|
||||
|
||||
<div class="col-xs-6">
|
||||
<div class="FSelect">
|
||||
<div class="arrow"></div>
|
||||
<div class="FCurValue">Month</div><select aria-label="Month" class="form-control"
|
||||
data-tooltip-special-pos="top left;bottom left" data-val="true"
|
||||
data-val-datemustbeequalorgreaterthancurrentdate="The credit card expiration date you provided has already expired."
|
||||
data-val-required="Expiry date" data-widget="lightcombobox" id="cardExpiryMonth"
|
||||
name="PaymentData.cardExpiryMonth" data-rendered="true" aria-required="true">
|
||||
<option selected="selected" value="">Month</option>
|
||||
<option value="1">01</option>
|
||||
<option value="2">02</option>
|
||||
<option value="3">03</option>
|
||||
<option value="4">04</option>
|
||||
<option value="5">05</option>
|
||||
<option value="6">06</option>
|
||||
<option value="7">07</option>
|
||||
<option value="8">08</option>
|
||||
<option value="9">09</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6">
|
||||
<div class="FSelect">
|
||||
<div class="arrow"></div>
|
||||
<div class="FCurValue">Year</div><select aria-label="Year" class="form-control"
|
||||
data-tooltip-special-pos="top right;bottom right" data-val="true"
|
||||
data-val-datemustbeequalorgreaterthancurrentdate="The credit card expiration date you provided has already expired."
|
||||
data-val-required="Expiry date" data-widget="lightcombobox" id="cardExpiryYear"
|
||||
name="PaymentData.cardExpiryYear" data-rendered="true" aria-required="true">
|
||||
<option selected="selected" value="">Year</option>
|
||||
<option value="2022">2022</option>
|
||||
<option value="2023">2023</option>
|
||||
<option value="2024">2024</option>
|
||||
<option value="2025">2025</option>
|
||||
<option value="2026">2026</option>
|
||||
<option value="2027">2027</option>
|
||||
<option value="2028">2028</option>
|
||||
<option value="2029">2029</option>
|
||||
<option value="2030">2030</option>
|
||||
<option value="2031">2031</option>
|
||||
<option value="2032">2032</option>
|
||||
<option value="2033">2033</option>
|
||||
<option value="2034">2034</option>
|
||||
<option value="2035">2035</option>
|
||||
<option value="2036">2036</option>
|
||||
<option value="2037">2037</option>
|
||||
<option value="2038">2038</option>
|
||||
<option value="2039">2039</option>
|
||||
<option value="2040">2040</option>
|
||||
<option value="2041">2041</option>
|
||||
<option value="2042">2042</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="cvvContainer" class="form-group">
|
||||
<label for="cvdNumber" class="col-sm-4 col-xs-12 control-label fcap paylabel">Security code<div
|
||||
data-show="true" class="glyphicon glyphicon-star astrsk"></div></label>
|
||||
<div class="col-sm-8 col-xs-12 fval">
|
||||
<input aria-label="Security code" autocomplete="off" class="form-control" data-tt-pos="top" data-val="true"
|
||||
data-val-cvvval="Please enter a valid CVV" data-val-cvvval-otherpropertyname=""
|
||||
data-val-required="Security code" id="cvdNumber" name="PaymentData.cvdNumber" pattern="[0-9]{3,4}"
|
||||
placeholder="CVV" type="tel" value="" aria-required="true">
|
||||
<span id="cvvDescriptionContainer" data-toggle="tooltip" data-placement="top" title=""
|
||||
data-original-title="The Security Code on your credit card or debit card is a 3 digit number on the back of your VISA®, MasterCard® and Discover® branded credit and debit cards. On your American Express® branded credit or debit card it is a 4 digit numeric code on the front of the card.">
|
||||
<label tabindex="0" class="control-label" id="cvvInfo"> What is this?</label>
|
||||
<label class="control-label secureinfolabel"><span class="secureInfo lazy"></span></label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--#region Hidden Payment Parameters-->
|
||||
<input type="hidden" name="PaymentData.checkoutV2" value="true">
|
||||
<input type="hidden" name="PaymentData.cartToken" id="cartToken" value="045078e1-dafa-4d42-8e1a-a8a8dc3c2234">
|
||||
<input type="hidden" name="PaymentData.gatewayId" id="gatewayId" value="2">
|
||||
<input type="hidden" name="PaymentData.paymentMethodId" id="paymentMethodId" value="1">
|
||||
<input type="hidden" name="PaymentData.machineId" id="machineId">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.createTransaction" id="createTransaction" value="true">
|
||||
<input type="hidden" name="PaymentData.checkoutCDNEnabled" id="checkoutURL" value="value">
|
||||
<input type="hidden" name="PaymentData.recapchaToken" id="recapchaToken">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.recapchaTime" id="recapchaTime">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.customerScreenColorDepth" id="customerScreenColorDepth">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.customerScreenWidth" id="customerScreenWidth">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.customerScreenHeight" id="customerScreenHeight">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.customerTimeZoneOffset" id="customerTimeZoneOffset">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.customerLanguage" id="customerLanguage">
|
||||
<!--Needs to be updated by script-->
|
||||
<input type="hidden" name="PaymentData.UrlStructureTokenEncoded" id="UrlStructureTokenEncoded"
|
||||
value="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJFbmNvZGVkTWVyY2hhbnRJZCI6IjhybzgiLCJDYXJ0VG9rZW4iOiIwNDUwNzhlMS1kYWZhLTRkNDItOGUxYS1hOGE4ZGMzYzIyMzQiLCJJc1JlcXVpcmVkVG9QYXlXaXRoRGVjb2RlZE1lcmNoYW50SWRBbmRUb2tlbkluVXJsIjpmYWxzZX0.NaxXTwl3w9OurCnPmosjy0P0kSvvs9JfY1OnRVI_w_4">
|
||||
<!--#endregion-->
|
||||
</form>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -16,6 +16,8 @@ skip-if = xorigin
|
|||
scheme=https
|
||||
[test_clear_form.html]
|
||||
scheme=https
|
||||
[test_clear_form_expiry_select_elements.html]
|
||||
scheme=https
|
||||
[test_creditcard_autocomplete_off.html]
|
||||
scheme=https
|
||||
[test_preview_highlight_with_multiple_cc_number_fields.html]
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test form autofill - clear form button with select elements</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="../formautofill_common.js"></script>
|
||||
<script type="text/javascript" src="../../../../../../toolkit/components/satchel/test/satchel_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
Form autofill test: clear form button with select elements.
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
const MOCK_ADDR_STORAGE = [{
|
||||
organization: "Sesame Street",
|
||||
"street-address": "2 Harrison St\nline2\nline3",
|
||||
tel: "+13453453456",
|
||||
}, {
|
||||
organization: "Mozilla",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
}, {
|
||||
organization: "Tel org",
|
||||
tel: "+12223334444",
|
||||
}];
|
||||
|
||||
const MOCK_CC_STORAGE = [{
|
||||
"cc-name": "John Doe",
|
||||
"cc-number": "4929001587121045",
|
||||
"cc-exp-month": 4,
|
||||
"cc-exp-year": 2017,
|
||||
}, {
|
||||
"cc-name": "Timothy Berners-Lee",
|
||||
"cc-number": "5103059495477870",
|
||||
"cc-exp-month": 12,
|
||||
"cc-exp-year": 2022,
|
||||
}];
|
||||
|
||||
initPopupListener();
|
||||
|
||||
add_task(async function setup_storage() {
|
||||
await addAddress(MOCK_ADDR_STORAGE[0]);
|
||||
await addCreditCard(MOCK_CC_STORAGE[0]);
|
||||
await addCreditCard(MOCK_CC_STORAGE[1]);
|
||||
});
|
||||
|
||||
|
||||
async function checkIsFormCleared(patch = {}) {
|
||||
const form = document.getElementById("form1");
|
||||
|
||||
for (const elem of form.elements) {
|
||||
const expectedValue = patch[elem.id] || "";
|
||||
checkFieldValue(elem, expectedValue);
|
||||
await checkFieldHighlighted(elem, false);
|
||||
await checkFieldPreview(elem, "");
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmClear(selector) {
|
||||
info("Await for clearing input");
|
||||
let promise = new Promise(resolve => {
|
||||
let beforeInputFired = false;
|
||||
let element = document.querySelector(selector);
|
||||
info(`Which element are we clearing? ${element.id}`);
|
||||
element.addEventListener("beforeinput", (event) => {
|
||||
beforeInputFired = true;
|
||||
ok(event instanceof InputEvent,
|
||||
'"beforeinput" event should be dispatched with InputEvent interface');
|
||||
is(event.cancelable, SpecialPowers.getBoolPref("dom.input_event.allow_to_cancel_set_user_input"),
|
||||
`"beforeinput" event should be cancelable unless it's disabled by the pref`);
|
||||
is(event.bubbles, true,
|
||||
'"beforeinput" event should always bubble');
|
||||
is(event.inputType, "insertReplacementText",
|
||||
'inputType value of "beforeinput" should be "insertReplacementText"');
|
||||
is(event.data, "",
|
||||
'data value of "beforeinput" should be empty string');
|
||||
is(event.dataTransfer, null,
|
||||
'dataTransfer value of "beforeinput" should be null');
|
||||
is(event.getTargetRanges().length, 0,
|
||||
'getTargetRanges() of "beforeinput" event should return empty array');
|
||||
}, {once: true});
|
||||
element.addEventListener("input", (event) => {
|
||||
ok(beforeInputFired, `"beforeinput" event should've been fired before "input" on <${element.tagName} type="${element.type}">`);
|
||||
ok(event instanceof InputEvent,
|
||||
'"input" event should be dispatched with InputEvent interface');
|
||||
is(event.cancelable, false,
|
||||
'"input" event should be never cancelable');
|
||||
is(event.bubbles, true,
|
||||
'"input" event should always bubble');
|
||||
is(event.inputType, "insertReplacementText",
|
||||
'inputType value of "input" should be "insertReplacementText"');
|
||||
is(event.data, "",
|
||||
'data value of "input" should be empty string');
|
||||
is(event.dataTransfer, null,
|
||||
'dataTransfer value of "input" should be null');
|
||||
is(event.getTargetRanges().length, 0,
|
||||
'getTargetRanges() of "input" should return empty array');
|
||||
resolve();
|
||||
}, {once: true})
|
||||
});
|
||||
synthesizeKey("KEY_Enter");
|
||||
await promise;
|
||||
}
|
||||
|
||||
// tgiles: We need this task due to timing issues between focusAndWaitForFieldsIdentified and popupShownListener.
|
||||
// There's a 300ms delay in focusAndWaitForFieldsIdentified that can cause triggerPopupAndHoverItem to get out of sync
|
||||
// and cause the popup to appear before the test expects a popup to appear.
|
||||
|
||||
// Without this task we end up either getting a consistent timeout or getting the following exception:
|
||||
// 0:20.55 GECKO(31108) JavaScript error: , line 0: uncaught exception: Checking selected index - timed out after 50 tries.
|
||||
// This exception appears if you attempt to create the expectPopup promise earlier than it currently is in triggetPopupAndHoverItem
|
||||
add_task(async function a_dummy_task() {
|
||||
await triggerPopupAndHoverItem("#organization", 0);
|
||||
await triggerAutofillAndCheckProfile(MOCK_ADDR_STORAGE[0]);
|
||||
|
||||
await triggerPopupAndHoverItem("#tel", 0);
|
||||
await confirmClear("#tel");
|
||||
await checkIsFormCleared({
|
||||
"cc-exp-month": "MM",
|
||||
"cc-exp-year": "YY"
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function clear_distinct_section() {
|
||||
if (!(await canTestOSKeyStoreLogin())) {
|
||||
todo(false, "Cannot test OS key store login on official builds.");
|
||||
return;
|
||||
}
|
||||
let osKeyStoreLoginShown = waitForOSKeyStoreLogin(true);
|
||||
await triggerPopupAndHoverItem("#cc-name", 0);
|
||||
await triggerAutofillAndCheckProfile(MOCK_CC_STORAGE[0]);
|
||||
await osKeyStoreLoginShown;
|
||||
|
||||
for (const [id, val] of Object.entries(MOCK_CC_STORAGE[0])) {
|
||||
const element = document.getElementById(id);
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
checkFieldValue(element, val);
|
||||
await checkFieldHighlighted(element, true);
|
||||
}
|
||||
|
||||
await triggerPopupAndHoverItem("#cc-name", 0);
|
||||
await confirmClear("#cc-name");
|
||||
await checkIsFormCleared({
|
||||
"cc-exp-month": "MM",
|
||||
"cc-exp-year": "YY"
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<p id="display"></p>
|
||||
|
||||
<div id="content">
|
||||
|
||||
<form id="form1">
|
||||
<p>This is a basic form.</p>
|
||||
<p><label>organization: <input id="organization" autocomplete="organization"></label></p>
|
||||
<p><label>streetAddress: <input id="street-address" autocomplete="street-address"></label></p>
|
||||
<p><label>tel: <input id="tel" autocomplete="tel"></label></p>
|
||||
<p><label>country: <input id="country" autocomplete="country"></label></p>
|
||||
|
||||
<p><label>Name: <input id="cc-name" autocomplete="cc-name"></label></p>
|
||||
<p><label>Card Number: <input id="cc-number" autocomplete="cc-number"></label></p>
|
||||
<!-- NOTE: If you're going to write a test like this,
|
||||
ensure that the selected option doesn't match the data that you're trying to autofill,
|
||||
otherwise your test will wait forever for an event that will never fire.
|
||||
I.e, if your saved cc-exp-month is 01, make sure your selected option ISN'T 01.
|
||||
-->
|
||||
<p><label>Expiration month: <select id="cc-exp-month" autocomplete="cc-exp-month">
|
||||
<option value="MM" selected>MM</option>
|
||||
<option value="1">01</option>
|
||||
<option value="2">02</option>
|
||||
<option value="3">03</option>
|
||||
<option value="4">04</option>
|
||||
<option value="5">05</option>
|
||||
<option value="6">06</option>
|
||||
<option value="7">07</option>
|
||||
<option value="8">08</option>
|
||||
<option value="9">09</option>
|
||||
<option value="10">10</option>
|
||||
<option value="11">11</option>
|
||||
<option value="12">12</option>
|
||||
</select>
|
||||
</label></p>
|
||||
<!-- NOTE: If you're going to write a test like this,
|
||||
ensure that the selected option doesn't match the data that you're trying to autofill,
|
||||
otherwise your test will wait forever for an event that will never fire.
|
||||
I.e, if your saved cc-exp-year is 2017, make sure your selected option ISN'T 2017.
|
||||
-->
|
||||
<p><label>Expiration year: <select id="cc-exp-year" autocomplete="cc-exp-year">
|
||||
<option value="YY" selected>YY</option>
|
||||
<option value="2017">2017</option>
|
||||
<option value="2018">2018</option>
|
||||
<option value="2019">2019</option>
|
||||
<option value="2020">2020</option>
|
||||
<option value="2021">2021</option>
|
||||
<option value="2022">2022</option>
|
||||
</select>
|
||||
</label></p>
|
||||
<p><label>CSC: <input id="cc-csc" autocomplete="cc-csc"></label></p>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</html>
|
42
browser/extensions/formautofill/test/unit/heuristics/third_party/test_DirectAsda.js
поставляемый
Normal file
42
browser/extensions/formautofill/test/unit/heuristics/third_party/test_DirectAsda.js
поставляемый
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* global runHeuristicsTest */
|
||||
|
||||
"use strict";
|
||||
|
||||
runHeuristicsTest(
|
||||
[
|
||||
{
|
||||
fixturePath: "Payment.html",
|
||||
expectedResult: [
|
||||
[
|
||||
[
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-number",
|
||||
},
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-name"
|
||||
},
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-exp-month"
|
||||
},
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-exp-year"
|
||||
},
|
||||
],
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
"../../../fixtures/third_party/DirectAsda/"
|
||||
)
|
36
browser/extensions/formautofill/test/unit/heuristics/third_party/test_GlobalDirectAsda.js
поставляемый
Normal file
36
browser/extensions/formautofill/test/unit/heuristics/third_party/test_GlobalDirectAsda.js
поставляемый
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* global runHeuristicsTest */
|
||||
|
||||
"use strict";
|
||||
|
||||
runHeuristicsTest(
|
||||
[
|
||||
{
|
||||
fixturePath: "Payment.html",
|
||||
expectedResult: [
|
||||
[
|
||||
[
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-number",
|
||||
},
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-exp-month"
|
||||
},
|
||||
{
|
||||
section: "",
|
||||
addressType: "",
|
||||
contactType: "",
|
||||
fieldName: "cc-exp-year"
|
||||
},
|
||||
],
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
"../../../fixtures/third_party/GlobalDirectAsda/"
|
||||
)
|
|
@ -12,9 +12,14 @@ skip-if = (os == "linux") && ccov # bug 1614100
|
|||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_CostCo.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_DirectAsda.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_GlobalDirectAsda.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_HomeDepot.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_Lufthansa.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_Macys.js]
|
||||
skip-if = (os == "linux") && ccov # bug 1614100
|
||||
[test_NewEgg.js]
|
||||
|
|
|
@ -304,7 +304,7 @@ const TESTCASES = [
|
|||
},
|
||||
{
|
||||
description:
|
||||
"Fill credit card fields in a form without a placeholder on expiration month input field",
|
||||
"Fill credit card fields in a form without a placeholder on expiration month and expiration year input fields",
|
||||
document: `<form>
|
||||
<input id="cc-number" autocomplete="cc-number">
|
||||
<input id="cc-name" autocomplete="cc-name">
|
||||
|
@ -327,6 +327,31 @@ const TESTCASES = [
|
|||
"cc-exp-year": "25",
|
||||
},
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Fill credit card fields in a form with a placeholder on expiration year input field",
|
||||
document: `<form>
|
||||
<input id="cc-number" autocomplete="cc-number">
|
||||
<input id="cc-name" autocomplete="cc-name">
|
||||
<input id="cc-exp-month" autocomplete="cc-exp-month">
|
||||
<input id="cc-exp-year" autocomplete="cc-exp-year" placeholder="YY">
|
||||
</form>
|
||||
`,
|
||||
focusedInputId: "cc-number",
|
||||
profileData: {
|
||||
guid: "123",
|
||||
"cc-number": "4111111111111111",
|
||||
"cc-name": "test name",
|
||||
"cc-exp-month": 6,
|
||||
"cc-exp-year": 2025,
|
||||
},
|
||||
expectedResult: {
|
||||
"cc-number": "4111111111111111",
|
||||
"cc-name": "test name",
|
||||
"cc-exp-month": "6",
|
||||
"cc-exp-year": "25",
|
||||
},
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Form with hidden input and visible input that share the same autocomplete attribute",
|
||||
|
@ -462,6 +487,31 @@ const TESTCASES = [
|
|||
"cc-exp-year2": "",
|
||||
},
|
||||
},
|
||||
{
|
||||
description:
|
||||
"Fill credit card fields in a form with placeholders on month and year and these inputs are type=tel",
|
||||
document: `<form>
|
||||
<input id="cardHolder">
|
||||
<input id="cardNumber">
|
||||
<input id="month" type="tel" name="month" placeholder="MM">
|
||||
<input id="year" type="tel" name="year" placeholder="YY">
|
||||
</form>
|
||||
`,
|
||||
focusedInputId: "cardHolder",
|
||||
profileData: {
|
||||
guid: "123",
|
||||
"cc-number": "4111111111111111",
|
||||
"cc-name": "test name",
|
||||
"cc-exp-month": 6,
|
||||
"cc-exp-year": 2025,
|
||||
},
|
||||
expectedResult: {
|
||||
cardHolder: "test name",
|
||||
cardNumber: "4111111111111111",
|
||||
month: "06",
|
||||
year: "25",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const TESTCASES_INPUT_UNCHANGED = [
|
||||
|
@ -753,11 +803,20 @@ function do_test(testcases, testFn) {
|
|||
let decryptHelper = async (cipherText, reauth) => {
|
||||
return OSKeyStore.decrypt(cipherText, false);
|
||||
};
|
||||
|
||||
handler.collectFormFields();
|
||||
|
||||
let focusedInput = doc.getElementById(testcase.focusedInputId);
|
||||
handler.focusedInput = focusedInput;
|
||||
try {
|
||||
handler.focusedInput = focusedInput;
|
||||
} catch (e) {
|
||||
if (e.message.includes("WeakMap key must be an object")) {
|
||||
throw new Error(
|
||||
`Couldn't find the focusedInputId in the current form! Make sure focusedInputId exists in your test form! testcase description:${testcase.description}`
|
||||
);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
for (let section of handler.sections) {
|
||||
section._decrypt = decryptHelper;
|
||||
|
|
|
@ -49,6 +49,10 @@ const getCCExpMonthFormatted = () => {
|
|||
return DEFAULT_CREDITCARD_RECORD["cc-exp-month"].toString().padStart(2, "0");
|
||||
};
|
||||
|
||||
const getCCExpYearFormatted = () => {
|
||||
return DEFAULT_CREDITCARD_RECORD["cc-exp-year"].toString().substring(2);
|
||||
};
|
||||
|
||||
const TESTCASES = [
|
||||
{
|
||||
description: "Address form with street-address",
|
||||
|
@ -1076,6 +1080,7 @@ const TESTCASES = [
|
|||
document: `<form>
|
||||
<input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp-month" placeholder="MM">
|
||||
<input autocomplete="cc-exp-year">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [
|
||||
|
@ -1084,6 +1089,20 @@ const TESTCASES = [
|
|||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp-year field [yy].",
|
||||
document: `<form>
|
||||
<input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp-month">
|
||||
<input autocomplete="cc-exp-year" placeholder="YY">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
"cc-exp-year-formatted": getCCExpYearFormatted(),
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Test maxlength=2 on numeric fields.",
|
||||
document: `<form>
|
||||
|
|
|
@ -22,6 +22,10 @@ const DEFAULT_CREDITCARD_RECORD = {
|
|||
"cc-exp": "2025-01",
|
||||
};
|
||||
|
||||
const getCCExpYearFormatted = () => {
|
||||
return DEFAULT_CREDITCARD_RECORD["cc-exp-year"].toString().substring(2);
|
||||
};
|
||||
|
||||
const FR_TESTCASES = [
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp format [mm/aa].",
|
||||
|
@ -89,6 +93,20 @@ const FR_TESTCASES = [
|
|||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp-year field [aa].",
|
||||
document: `<form>
|
||||
<input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp-month">
|
||||
<input autocomplete="cc-exp-year" placeholder="AA">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
"cc-exp-year-formatted": getCCExpYearFormatted(),
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const DE_TESTCASES = [
|
||||
|
@ -191,6 +209,20 @@ const DE_TESTCASES = [
|
|||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
description: "Use placeholder to adjust cc-exp-year field [jj].",
|
||||
document: `<form>
|
||||
<input autocomplete="cc-number">
|
||||
<input autocomplete="cc-exp-month">
|
||||
<input autocomplete="cc-exp-year" placeholder="JJ">
|
||||
</form>`,
|
||||
profileData: [Object.assign({}, DEFAULT_CREDITCARD_RECORD)],
|
||||
expectedResult: [
|
||||
Object.assign({}, DEFAULT_CREDITCARD_RECORD, {
|
||||
"cc-exp-year-formatted": getCCExpYearFormatted(),
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const TESTCASES = [FR_TESTCASES, DE_TESTCASES];
|
||||
|
|
|
@ -422,7 +422,10 @@ class FormAutofillSection {
|
|||
|
||||
for (let fieldDetail of this.fieldDetails) {
|
||||
let element = fieldDetail.elementWeakRef.get();
|
||||
let value = profile[fieldDetail.fieldName] || "";
|
||||
let value =
|
||||
profile[`${fieldDetail.fieldName}-formatted`] ||
|
||||
profile[fieldDetail.fieldName] ||
|
||||
"";
|
||||
|
||||
// Skip the field that is null
|
||||
if (!element) {
|
||||
|
@ -732,6 +735,12 @@ class FormAutofillSection {
|
|||
option.hasAttribute("selected")
|
||||
);
|
||||
element.value = selected ? selected.value : element.options[0].value;
|
||||
element.dispatchEvent(
|
||||
new element.ownerGlobal.Event("input", { bubbles: true })
|
||||
);
|
||||
element.dispatchEvent(
|
||||
new element.ownerGlobal.Event("change", { bubbles: true })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1071,7 +1080,14 @@ class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||
);
|
||||
}
|
||||
|
||||
creditCardExpDateTransformer(profile) {
|
||||
/**
|
||||
* Handles credit card expiry date transformation when
|
||||
* the expiry date exists in a cc-exp field.
|
||||
*
|
||||
* @param {object} profile
|
||||
* @memberof FormAutofillCreditCardSection
|
||||
*/
|
||||
creditCardExpiryDateTransformer(profile) {
|
||||
if (!profile["cc-exp"]) {
|
||||
return;
|
||||
}
|
||||
|
@ -1145,23 +1161,31 @@ class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||
}
|
||||
}
|
||||
|
||||
creditCardExpMonthTransformer(profile) {
|
||||
if (!profile["cc-exp-month"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let detail = this.getFieldDetailByName("cc-exp-month");
|
||||
if (!detail) {
|
||||
return;
|
||||
}
|
||||
|
||||
let element = detail.elementWeakRef.get();
|
||||
|
||||
/**
|
||||
* Handles credit card expiry date transformation when the expiry date exists in
|
||||
* the separate cc-exp-month and cc-exp-year fields
|
||||
*
|
||||
* @param {object} profile
|
||||
* @memberof FormAutofillCreditCardSection
|
||||
*/
|
||||
creditCardExpMonthAndYearTransformer(profile) {
|
||||
const getInputElementByField = (field, self) => {
|
||||
if (!field) {
|
||||
return null;
|
||||
}
|
||||
let detail = self.getFieldDetailByName(field);
|
||||
if (!detail) {
|
||||
return null;
|
||||
}
|
||||
let element = detail.elementWeakRef.get();
|
||||
return element.tagName === "INPUT" ? element : null;
|
||||
};
|
||||
let month = getInputElementByField("cc-exp-month", this);
|
||||
// If the expiration month element is an input,
|
||||
// then we examine any placeholder to see if we should format the expiration month
|
||||
// as a zero padded string in order to autofill correctly.
|
||||
if (element.tagName === "INPUT") {
|
||||
let placeholder = element.placeholder;
|
||||
if (month) {
|
||||
let placeholder = month.placeholder;
|
||||
|
||||
// Checks for 'MM' placeholder and converts the month to a two digit string.
|
||||
let result = /(?<!.)mm(?!.)/i.test(placeholder);
|
||||
|
@ -1171,6 +1195,22 @@ class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||
.padStart(2, "0");
|
||||
}
|
||||
}
|
||||
|
||||
let year = getInputElementByField("cc-exp-year", this);
|
||||
// If the expiration year element is an input,
|
||||
// then we examine any placeholder to see if we should format the expiration year
|
||||
// as a zero padded string in order to autofill correctly.
|
||||
if (year) {
|
||||
let placeholder = year.placeholder;
|
||||
|
||||
// Checks for 'YY'|'AA'|'JJ' placeholder and converts the year to a two digit string using the last two digits.
|
||||
let result = /(?<!.)(yy|aa|jj)(?!.)/i.test(placeholder);
|
||||
if (result) {
|
||||
profile["cc-exp-year-formatted"] = profile["cc-exp-year"]
|
||||
.toString()
|
||||
.substring(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async _decrypt(cipherText, reauth) {
|
||||
|
@ -1206,8 +1246,8 @@ class FormAutofillCreditCardSection extends FormAutofillSection {
|
|||
// This ensures that the expiry value that is cached in the matchSelectOptions
|
||||
// matches the expiry value that is stored in the profile ensuring that autofill works
|
||||
// correctly when dealing with option elements.
|
||||
this.creditCardExpDateTransformer(profile);
|
||||
this.creditCardExpMonthTransformer(profile);
|
||||
this.creditCardExpiryDateTransformer(profile);
|
||||
this.creditCardExpMonthAndYearTransformer(profile);
|
||||
this.matchSelectOptions(profile);
|
||||
this.adaptFieldMaxLength(profile);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable prettier/prettier */
|
||||
/* eslint-disable no-useless-concat */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
@ -48,14 +50,17 @@ var HeuristicsRegExp = {
|
|||
"address-level1": "land", // de-DE
|
||||
"additional-name": "apellido.?materno|lastlastname",
|
||||
"cc-name":
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
"accountholdername" +
|
||||
"accountholdername" +
|
||||
"|titulaire", // fr-FR
|
||||
"cc-number": "(cc|kk)nr", // de-DE
|
||||
"cc-exp-month": "(cc|kk)month", // de-DE
|
||||
"cc-exp-year": "(cc|kk)year", // de-DE
|
||||
// eslint-disable-next-line prettier/prettier
|
||||
"cc-type": "type" +
|
||||
"cc-exp-month":
|
||||
"month" +
|
||||
"|(cc|kk)month", // de-DE
|
||||
"cc-exp-year":
|
||||
"year" +
|
||||
"|(cc|kk)year", // de-DE
|
||||
"cc-type":
|
||||
"type" +
|
||||
"|kartenmarke", // de-DE
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче