Commit 38ba5ed2 authored by Luke Zielinski's avatar Luke Zielinski Committed by Commit Bot

Add support to wpt_metadata_builder for using checked-in wpt metadata.

This also includes a generated set of metadata for the payments API.

Bug: 1116091
Change-Id: Ie73e27eb79c3dbd7b9512418f2f3661ae5fe73dc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2327138
Commit-Queue: Luke Z <lpz@chromium.org>
Reviewed-by: default avatarRobert Ma <robertma@chromium.org>
Reviewed-by: default avatarStephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799661}
parent a7170675
...@@ -21,7 +21,8 @@ import sys ...@@ -21,7 +21,8 @@ import sys
import common import common
import wpt_common import wpt_common
WPT_METADATA_DIR = "../../wpt_expectations_metadata/" WPT_CHECKED_IN_METADATA_DIR = "../../third_party/blink/web_tests/external/wpt"
WPT_METADATA_OUTPUT_DIR = "../../wpt_expectations_metadata/"
WPT_OVERRIDE_EXPECTATIONS_PATH = ( WPT_OVERRIDE_EXPECTATIONS_PATH = (
"../../third_party/blink/web_tests/WPTOverrideExpectations") "../../third_party/blink/web_tests/WPTOverrideExpectations")
...@@ -57,7 +58,7 @@ class WPTTestAdapter(wpt_common.BaseWptScriptAdapter): ...@@ -57,7 +58,7 @@ class WPTTestAdapter(wpt_common.BaseWptScriptAdapter):
# those that had non-zero exit codes). # those that had non-zero exit codes).
#"--no-fail-on-unexpected", #"--no-fail-on-unexpected",
"--metadata", "--metadata",
WPT_METADATA_DIR, WPT_METADATA_OUTPUT_DIR,
# By specifying metadata above, WPT will try to find manifest in the # By specifying metadata above, WPT will try to find manifest in the
# metadata directory. So here we point it back to the correct path # metadata directory. So here we point it back to the correct path
# for the manifest. # for the manifest.
...@@ -85,9 +86,11 @@ def main(): ...@@ -85,9 +86,11 @@ def main():
sys.executable, sys.executable,
os.path.join(wpt_common.BLINK_TOOLS_DIR, 'build_wpt_metadata.py'), os.path.join(wpt_common.BLINK_TOOLS_DIR, 'build_wpt_metadata.py'),
"--metadata-output-dir", "--metadata-output-dir",
WPT_METADATA_DIR, WPT_METADATA_OUTPUT_DIR,
"--additional-expectations", "--additional-expectations",
WPT_OVERRIDE_EXPECTATIONS_PATH WPT_OVERRIDE_EXPECTATIONS_PATH,
"--checked-in-metadata-dir",
WPT_CHECKED_IN_METADATA_DIR
]) ])
adapter = WPTTestAdapter() adapter = WPTTestAdapter()
......
...@@ -10,12 +10,13 @@ running the WPT test suite. ...@@ -10,12 +10,13 @@ running the WPT test suite.
""" """
import argparse import argparse
import fnmatch
import logging import logging
import os import os
import re import re
from blinkpy.common.system.filesystem import FileSystem
from blinkpy.common.system.log_utils import configure_logging from blinkpy.common.system.log_utils import configure_logging
from blinkpy.web_tests.models import test_expectations
from blinkpy.web_tests.models.typ_types import ResultType from blinkpy.web_tests.models.typ_types import ResultType
from collections import defaultdict from collections import defaultdict
...@@ -50,8 +51,11 @@ class WPTMetadataBuilder(object): ...@@ -50,8 +51,11 @@ class WPTMetadataBuilder(object):
""" """
self.expectations = expectations self.expectations = expectations
self.port = port self.port = port
# TODO(lpz): Use self.fs everywhere in this class and add tests
self.fs = FileSystem()
self.wpt_manifest = self.port.wpt_manifest("external/wpt") self.wpt_manifest = self.port.wpt_manifest("external/wpt")
self.metadata_output_dir = "" self.metadata_output_dir = ""
self.checked_in_metadata_dir = ""
def run(self, args=None): def run(self, args=None):
"""Main entry point to parse flags and execute the script.""" """Main entry point to parse flags and execute the script."""
...@@ -59,6 +63,11 @@ class WPTMetadataBuilder(object): ...@@ -59,6 +63,11 @@ class WPTMetadataBuilder(object):
parser.add_argument( parser.add_argument(
"--metadata-output-dir", "--metadata-output-dir",
help="The directory to output the metadata files into.") help="The directory to output the metadata files into.")
parser.add_argument(
"--checked-in-metadata-dir",
help="Root directory of any checked-in WPT metadata files to use. "
"If set, these files will take precedence over legacy expectations "
"and baselines when both exist for a test.")
parser.add_argument( parser.add_argument(
'-v', '-v',
'--verbose', '--verbose',
...@@ -70,6 +79,7 @@ class WPTMetadataBuilder(object): ...@@ -70,6 +79,7 @@ class WPTMetadataBuilder(object):
configure_logging(logging_level=log_level, include_time=True) configure_logging(logging_level=log_level, include_time=True)
self.metadata_output_dir = args.metadata_output_dir self.metadata_output_dir = args.metadata_output_dir
self.checked_in_metadata_dir = args.checked_in_metadata_dir
self._build_metadata_and_write() self._build_metadata_and_write()
return 0 return 0
...@@ -121,12 +131,40 @@ class WPTMetadataBuilder(object): ...@@ -121,12 +131,40 @@ class WPTMetadataBuilder(object):
continue continue
self._write_to_file(filename, file_contents) self._write_to_file(filename, file_contents)
if self.checked_in_metadata_dir and os.path.exists(
self.checked_in_metadata_dir):
_log.info("Copying checked-in WPT metadata on top of translated "
"files.")
self._copy_checked_in_metadata()
else:
_log.warning("Not using checked-in WPT metadata, path is empty or "
"does not exist: %s" % self.checked_in_metadata_dir)
# Finally, output a stamp file with the same name as the output # Finally, output a stamp file with the same name as the output
# directory. The stamp file is empty, it's only used for its mtime. # directory. The stamp file is empty, it's only used for its mtime.
# This makes the GN build system happy (see crbug.com/995112). # This makes the GN build system happy (see crbug.com/995112).
with open(self.metadata_output_dir + ".stamp", "w"): with open(self.metadata_output_dir + ".stamp", "w"):
pass pass
def _copy_checked_in_metadata(self):
"""Copies checked-in metadata files to the metadata output directory."""
for filename in self.fs.files_under(self.checked_in_metadata_dir):
# We match any .ini files in the path. This will find .ini files
# other than just metadata (such as tox.ini), but that is ok
# since wptrunner will just ignore those.
if not fnmatch.fnmatch(filename, "*.ini"):
continue
# Found a checked-in .ini file. Copy it to the metadata output
# directory in the same sub-path as where it is checked in.
# So /checked/in/a/b/c.ini goes to /metadata/out/a/b/c.ini
output_path = filename.replace(self.checked_in_metadata_dir,
self.metadata_output_dir)
if not self.fs.exists(self.fs.dirname(output_path)):
self.fs.maybe_make_directory(self.fs.dirname(output_path))
_log.debug("Copying %s to %s" % (filename, output_path))
self.fs.copyfile(filename, output_path)
def _write_to_file(self, filename, file_contents): def _write_to_file(self, filename, file_contents):
# Write the contents to the file name # Write the contents to the file name
if not os.path.exists(os.path.dirname(filename)): if not os.path.exists(os.path.dirname(filename)):
......
...@@ -8,6 +8,7 @@ import os ...@@ -8,6 +8,7 @@ import os
import unittest import unittest
from blinkpy.common.host_mock import MockHost from blinkpy.common.host_mock import MockHost
from blinkpy.common.system.filesystem_mock import MockFileSystem
from blinkpy.web_tests.models.test_expectations import TestExpectations from blinkpy.web_tests.models.test_expectations import TestExpectations
from blinkpy.web_tests.port.factory_mock import MockPortFactory from blinkpy.web_tests.port.factory_mock import MockPortFactory
from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME from blinkpy.w3c.wpt_manifest import BASE_MANIFEST_NAME
...@@ -412,3 +413,42 @@ class WPTMetadataBuilderTest(unittest.TestCase): ...@@ -412,3 +413,42 @@ class WPTMetadataBuilderTest(unittest.TestCase):
"test.worker.html?variant=abc", "test.worker.html?variant=abc",
mb._metadata_inline_test_name_from_test_name( mb._metadata_inline_test_name_from_test_name(
"dir/test.worker.html?variant=abc")) "dir/test.worker.html?variant=abc"))
def test_copy_checked_in_metadata(self):
# Ensure that ini metadata files are copied from the checked-in dir to
# the output dir as expected.
expectations = TestExpectations(self.port)
mb = WPTMetadataBuilder(expectations, self.port)
# Set the metadata builder to use mock filesystem populated with some
# test data
mb.checked_in_metadata_dir = "src"
mb.metadata_output_dir = "out"
mock_checked_in_files = {
"src/a/b/c.html": "",
"src/a/b/c.html.ini": "",
"src/a/d/e.html": "",
"src/a/d/e.html.ini": "checked-in",
"src/a/tox.ini": "",
# Put one duplicate file in the output directory to simulate a test
# with both legacy expectations and checked-in metadata
"out/a/d/e.html.ini": "legacy",
}
mb.fs = MockFileSystem(files=mock_checked_in_files)
# Ensure that the duplicate file starts out with the legacy content.
duplicate_ini_file = "out/a/d/e.html.ini"
self.assertEqual("legacy", mb.fs.read_text_file(duplicate_ini_file))
mb._copy_checked_in_metadata()
# Ensure only the ini files are copied, not the tests
self.assertEqual(3, len(mb.fs.written_files))
self.assertTrue("out/a/b/c.html.ini" in mb.fs.written_files)
self.assertTrue("out/a/d/e.html.ini" in mb.fs.written_files)
self.assertTrue("out/a/tox.ini" in mb.fs.written_files)
# Also ensure that the content of the duplicate file was overwritten
# with the checked-in contents.
self.assertEqual("checked-in",
mb.fs.read_text_file(duplicate_ini_file))
[can-make-payment-event.https.html]
[If CanMakePaymentEvent.respondWith(Promise.resolve(true)) is called, then the payment method is supported.]
expected: FAIL
[If an app supports "basic-card" in general and that's what merchant requests as well, then capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
expected: FAIL
[If CanMakePaymentEvent.respondWith(false) is called, then the payment method is not supported.]
expected: FAIL
[If CanMakePaymentEvent.respondWith(Promise.reject(error)) is called, then the payment method is not supported.]
expected: FAIL
[If CanMakePaymentEvent.respondWith(true) is called, then the payment method is supported.]
expected: FAIL
[If an app has the exact "basic-card" capabilities that a merchant requested, capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
expected: FAIL
[If a payment handler is not installed, then the payment method is not supported.]
expected: FAIL
[If CanMakePaymentEvent.respondWith(Promise.resolve(false)) is called, then the payment method is not supported.]
expected: FAIL
[If an app has less specific "basic-card" capabilites than merchant's request, capability filtering should not make the app available for use. CanMakePaymentEvent should not be fired for "basic-card". ]
expected: FAIL
[If an app has more specific "basic-card" capabilities than merchant's request, capability filtering should make the app available for use. CanMakePaymentEvent should not be fired for "basic-card".]
expected: FAIL
[idlharness.https.any.html]
[idlharness.https.any.worker.html]
[PaymentManager interface: attribute userHint]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[PaymentManager interface object length]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[PaymentManager interface object name]
expected: FAIL
[PaymentManager interface: attribute instruments]
expected: FAIL
[PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>)]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object]
expected: FAIL
[PaymentManager interface: existence and properties of interface object]
expected: FAIL
[idlharness.https.any.serviceworker.html]
[CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "methodData" with the proper type]
expected: FAIL
[CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "respondWith(Promise<boolean>)" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "instrumentKey" with the proper type]
expected: FAIL
[PaymentManager interface: attribute instruments]
expected: FAIL
[CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "paymentRequestOrigin" with the proper type]
expected: FAIL
[PaymentManager interface: attribute userHint]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[PaymentRequestEvent interface: calling respondWith(Promise<PaymentHandlerResponse>) on new PaymentRequestEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[PaymentManager must be primary interface of paymentManager]
expected: FAIL
[PaymentRequestEvent interface: calling changeShippingOption(DOMString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[PaymentRequestEvent interface object length]
expected: FAIL
[PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>)]
expected: FAIL
[Stringification of new PaymentRequestEvent("type")]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentOptions" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "respondWith(Promise<PaymentHandlerResponse>)" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "shippingOptions" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingAddress(optional AddressInit)" with the proper type]
expected: FAIL
[PaymentManager interface object length]
expected: FAIL
[PaymentManager interface object name]
expected: FAIL
[PaymentRequestEvent interface: calling changeShippingAddress(optional AddressInit) on new PaymentRequestEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[CanMakePaymentEvent must be primary interface of new CanMakePaymentEvent("type")]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "methodData" with the proper type]
expected: FAIL
[CanMakePaymentEvent interface: calling respondWith(Promise<boolean>) on new CanMakePaymentEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[CanMakePaymentEvent interface: new CanMakePaymentEvent("type") must inherit property "topOrigin" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "openWindow(USVString)" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: calling changePaymentMethod(DOMString, optional object?) on new PaymentRequestEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changeShippingOption(DOMString)" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "modifiers" with the proper type]
expected: FAIL
[Stringification of new CanMakePaymentEvent("type")]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentRequestOrigin" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: calling openWindow(USVString) on new PaymentRequestEvent("type") with too few arguments must throw TypeError]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "topOrigin" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "requestBillingAddress" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "total" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "changePaymentMethod(DOMString, optional object?)" with the proper type]
expected: FAIL
[PaymentRequestEvent must be primary interface of new PaymentRequestEvent("type")]
expected: FAIL
[PaymentRequestEvent interface: attribute requestBillingAddress]
expected: FAIL
[PaymentRequestEvent interface: new PaymentRequestEvent("type") must inherit property "paymentRequestId" with the proper type]
expected: FAIL
[PaymentRequestEvent interface: operation changeShippingAddress(optional AddressInit)]
expected: FAIL
[CanMakePaymentEvent interface object length]
expected: FAIL
[PaymentManager interface: existence and properties of interface object]
expected: FAIL
[idlharness.https.any.sharedworker.html]
[PaymentManager interface: attribute userHint]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[PaymentManager interface object length]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[PaymentManager interface object name]
expected: FAIL
[PaymentManager interface: attribute instruments]
expected: FAIL
[PaymentManager interface: operation enableDelegations(sequence<PaymentDelegation>)]
expected: FAIL
[PaymentManager interface: existence and properties of interface prototype object]
expected: FAIL
[PaymentManager interface: existence and properties of interface object]
expected: FAIL
[payment-instruments.https.html]
[Resetting an existing instrument updates the instrument]
expected: FAIL
[Clearing the instruments]
expected: FAIL
[Don't crash when registering instruments with very long icon media type image/pngggggg...]
expected: FAIL
[Cannot register instruments with an existing non-https icon URL]
expected: FAIL
[Deleting an existing instrument returns true]
expected: FAIL
[Don't crash on very long key, name, method, and capability strings.]
expected: FAIL
[Don't crash on null characters in key, name, method, and capability strings.]
expected: FAIL
[Don't crash when registering an instrument with a very long icon size 888...x888...]
expected: FAIL
[Cannot register instruments with invalid icon media type image/jif]
expected: FAIL
[Instrument keys are returned in the original insertion order]
expected: FAIL
[Cannot register instruments with invalid icon URL (has a null character)]
expected: FAIL
[Deleting an existing instrument the second time returns false]
expected: FAIL
[Cannot register instruments with non-existing non-https icon URL]
expected: FAIL
[Getting an existing instrument returns the instrument]
expected: FAIL
[Cannot register instruments with invalid icon size "256 256" (missing "x")]
expected: FAIL
[respond-with-minimal-ui.https.html]
[respondWithMinimalUI({}) causes hasEnrolledInstrument() to return "false"]
expected: FAIL
[respondWithMinimalUI({canMakePayment: true, readyForMinimalUI: true, accountBalance: "6.78"}) does not crash]
expected: FAIL
[respondWithMinimalUI(0) causes hasEnrolledInstrument() to return "false"]
expected: FAIL
[respondWithMinimalUI({canMakePayment: true}) causes hasEnrolledInstrument() to return "true"]
expected: FAIL
[respondWithMinimalUI({canMakePayment: true, readyForMinimalUI: true, accountBalance: "--"}) does not crash]
expected: FAIL
[respondWithMinimalUI({canMakePayment: false}) causes hasEnrolledInstrument() to return "false"]
expected: FAIL
[respondWithMinimalUI({canMakePayment: true, readyForMinimalUI: true, accountBalance: ""}) does not crash]
expected: FAIL
[respondWithMinimalUI({canMakePayment: true, readyForMinimalUI: true}) does not crash]
expected: FAIL
[payment-request-canmakepayment-method.https.html]
[Must return false when the PMI is not supported at by the user agent.]
expected: FAIL
[If basic-card is supported, then return a promise that resolves to true.]
expected: FAIL
[Must return true when basic-card is amongst unsupported PMIs.]
expected: FAIL
[active-document-cross-origin.https.sub.html]
[PaymentRequest <iframe allowpaymentrequest> in non-active document (cross-origin)]
expected: FAIL
[active-document-same-origin.https.html]
[PaymentRequest <iframe allowpaymentrequest> in non-active document (same-origin)]
expected: FAIL
[constructor_convert_method_data.https.html]
[Converts PaymentMethodData's data to mandated IDL type during PaymentRequest construction.]
expected: FAIL
[idlharness.https.window.html]
[PaymentRequest interface: attribute onmerchantvalidation]
expected: FAIL
[PaymentRequest interface object length]
expected: FAIL
[PaymentRequest interface: paymentRequest must inherit property "onmerchantvalidation" with the proper type]
expected: FAIL
[onmerchantvalidation-attribute.https.html]
[onmerchantvalidation attribute and listeners both work]
expected: FAIL
[Must have a onmerchantvalidation IDL attribute]
expected: FAIL
[onmerchantvalidation attribute is a generic handler for "merchantvalidation"]
expected: FAIL
[onmerchantvalidation attribute is a handler for MerchantValidationEvent]
expected: FAIL
[payment-is-showing.https.html]
expected: ERROR
[Given multiple nested browsing contexts, and an iframe calls show() first, other nested browsing contexts can't show a request.]
expected: FAIL
[Using a popup window prevents the top-browsing context from showing a payment request]
expected: FAIL
[An iframe cannot show a payment request if the top-level window is already showing one.]
expected: FAIL
[Given multiple nested browsing contexts, and popup calls show() first, other nested browsing contexts can't show a request.]
expected: FAIL
[The top browsing context can only show one payment sheet at a time.]
expected: FAIL
[Navigating an iframe as a nested browsing context sets 'payment request is showing boolean' to false.]
expected: TIMEOUT
[Given multiple nested browsing contexts, and window calls show() first, other nested browsing contexts can't show a request.]
expected: FAIL
[If an iframe shows a payment request, the top-level browsing context can't also show one.]
expected: FAIL
[Navigating a popup as a nested browsing context sets 'payment request is showing boolean' to false.]
expected: NOTRUN
[payment-request-abort-method.https.html]
[Aborting a request before it is shown doesn't prevent it from being shown later.]
expected: FAIL
[The same request cannot be shown multiple times.]
expected: FAIL
[payment-request-canmakepayment-method-protection.https.html]
[Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.]
expected: FAIL
[payment-request-canmakepayment-method.https.html]
expected: ERROR
[If payment method identifier are supported, resolve promise with true.]
expected: FAIL
[Mix of supported and unsupported methods, at least one method is supported.]
expected: FAIL
[If request.[[state\]\] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.]
expected: FAIL
[If request.[[state\]\] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.]
expected: FAIL
[All methods are unsupported]
expected: FAIL
[If request.[[state\]\] is "created", then return a promise that resolves to true for known method.]
expected: FAIL
[payment-request-hasenrolledinstrument-method-protection.tentative.https.html]
[Optionally, at the user agent's discretion, return a promise rejected with a "NotAllowedError" DOMException.]
expected: FAIL
[payment-request-hasenrolledinstrument-method.tentative.https.html]
[If request.[[state\]\] is "interactive", then return a promise rejected with an "InvalidStateError" DOMException.]
expected: FAIL
[If request.[[state\]\] is "closed", then return a promise rejected with an "InvalidStateError" DOMException.]
expected: FAIL
[hasEnrolledInstrument() resolves to false for unsupported payment methods.]
expected: FAIL
[payment-request-show-method.https.html]
[Throws if the promise [[state\]\] is not 'created'.]
expected: FAIL
[If payment method consultation produces no supported method of payment, then return a promise rejected with a "NotSupportedError" DOMException.]
expected: FAIL
[Calling show() multiple times always returns a new promise.]
expected: FAIL
[If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException.]
expected: FAIL
[Calling show() without being triggered by user interaction throws]
expected: FAIL
[rejects_if_not_active.https.html]
[If a payment request is showing, but its document is navigated away (so no longer fully active), the payment sheet is dismissed.]
expected: FAIL
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment