diff --git a/dist/autofill-debug.js b/dist/autofill-debug.js index 9ccabd40e..ef017be86 100644 --- a/dist/autofill-debug.js +++ b/dist/autofill-debug.js @@ -13656,8 +13656,8 @@ class Matching { } this.setActiveElementStrings(input, formEl); - if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // // For CC forms we run aggressive matches, so we want to make sure we only - // // run them on actual CC forms to avoid false positives and expensive loops + if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // For CC forms we run aggressive matches, so we want to make sure we only + // run them on actual CC forms to avoid false positives and expensive loops if (opts.isCCForm) { const subtype = this.subtypeFromMatchers('cc', input); diff --git a/dist/autofill.js b/dist/autofill.js index 36465880d..f4601f47b 100644 --- a/dist/autofill.js +++ b/dist/autofill.js @@ -9980,8 +9980,8 @@ class Matching { } this.setActiveElementStrings(input, formEl); - if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // // For CC forms we run aggressive matches, so we want to make sure we only - // // run them on actual CC forms to avoid false positives and expensive loops + if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // For CC forms we run aggressive matches, so we want to make sure we only + // run them on actual CC forms to avoid false positives and expensive loops if (opts.isCCForm) { const subtype = this.subtypeFromMatchers('cc', input); diff --git a/integration-test/helpers/harness.js b/integration-test/helpers/harness.js index f4ba159e4..230b26cfc 100644 --- a/integration-test/helpers/harness.js +++ b/integration-test/helpers/harness.js @@ -33,12 +33,19 @@ export async function withEmailProtectionExtensionSignedInAs (page, username) { } /** - * @param {import("@playwright/test").Page} page - * @param {Record} replacements - * @param {Platform} [platform] + * @param {object} p + * @param {import("@playwright/test").Page} p.page + * @param {Record} p.replacements + * @param {Platform} [p.platform] + * @param {{ + * MAX_INPUTS_PER_PAGE: number, + * MAX_FORMS_PER_PAGE: number, + * MAX_INPUTS_PER_FORM: number, + * MAX_FORM_MUT_OBS_COUNT: number + * }} [p.constants] * @return {Promise} */ -function withStringReplacements (page, replacements, platform = 'macos') { +function withStringReplacements ({page, replacements, platform = 'macos', constants}) { const content = readFileSync('./dist/autofill.js', 'utf8') let output = content for (let [keyName, value] of Object.entries(replacements)) { @@ -48,6 +55,12 @@ function withStringReplacements (page, replacements, platform = 'macos') { output = output.replace(`// INJECT ${keyName} HERE`, `${keyName} = ${replacement};`) } + if (constants) { + for (let [keyName, value] of Object.entries(constants)) { + output = output.replace(new RegExp(`${keyName}: \\d+`), `${keyName}: ${value}`) + } + } + // 'macos' + 'ios' can execute scripts before page scripts if (['macos', 'ios'].includes(platform)) { return page.addInitScript(output) @@ -98,6 +111,13 @@ export function createAutofillScript () { /** @type {Platform} */ let platform = 'macos' + let constants = { + MAX_INPUTS_PER_PAGE: 100, + MAX_FORMS_PER_PAGE: 30, + MAX_INPUTS_PER_FORM: 80, + MAX_FORM_MUT_OBS_COUNT: 50 + } + /** @type {ScriptBuilder} */ const builder = { replace (key, value) { @@ -116,11 +136,15 @@ export function createAutofillScript () { platform = p return this }, + withConstants (consts) { + constants = consts + return this + }, async applyTo (page) { if (platform === 'windows') { replacements['isWindows'] = true } - return withStringReplacements(page, replacements, platform) + return withStringReplacements({page, replacements, platform, constants}) } } @@ -190,6 +214,8 @@ export function forwardConsoleMessages (page, _opts = {}) { * @return {Promise} */ export async function performanceEntries (page, measureName) { + // don't measure until the entries exist + await page.waitForFunction((measureName) => window.performance.getEntriesByName(measureName).length > 0, `${measureName}:end`) const result = await page.evaluate((measureName) => { window.performance?.measure?.(measureName, `${measureName}:start`, `${measureName}:end`) const entries = window.performance?.getEntriesByName(measureName) diff --git a/integration-test/helpers/harness.types.d.ts b/integration-test/helpers/harness.types.d.ts index 29a3cbdba..251763bd3 100644 --- a/integration-test/helpers/harness.types.d.ts +++ b/integration-test/helpers/harness.types.d.ts @@ -80,6 +80,8 @@ interface ScriptBuilder { tap(fn: (replacements: Partial, platform: string) => void): Omit // set the platform - this is required platform(platform: Platform): Omit + // can alter constants as defined in src/constants.js if needed + withConstants(constants: any): Omit // apply to the page, this is the final step applyTo(page: import("@playwright/test").Page): Promise } diff --git a/integration-test/helpers/mocks.js b/integration-test/helpers/mocks.js index a6b0cf534..6e62c6109 100644 --- a/integration-test/helpers/mocks.js +++ b/integration-test/helpers/mocks.js @@ -7,6 +7,7 @@ export const constants = { 'email-autofill': 'pages/email-autofill.html', 'emailAtBottom': 'pages/email-at-bottom.html', 'emailAtTopLeft': 'pages/email-at-top-left.html', + 'scanner-perf': 'pages/scanner-perf.html', 'iframeContainer': 'pages/iframe-container.html', 'signup': 'pages/signup.html', 'mutatingForm': 'pages/mutating-form.html', diff --git a/integration-test/helpers/pages.js b/integration-test/helpers/pages.js index 8138593be..5baf556e2 100644 --- a/integration-test/helpers/pages.js +++ b/integration-test/helpers/pages.js @@ -1,6 +1,6 @@ import { constants } from './mocks.js' import { expect } from '@playwright/test' -import {mockedCalls, payloadsOnly} from './harness.js' +import {mockedCalls, payloadsOnly, performanceEntries} from './harness.js' import {addTopAutofillMouseFocus, clickOnIcon} from './utils.js' const ATTR_AUTOFILL = 'data-ddg-autofill' @@ -739,3 +739,27 @@ export function overlayPage (page) { return new OverlayPage() } + +/** + * A wrapper around interactions for `integration-test/pages/scanner-perf.html` + * + * @param {import("@playwright/test").Page} page + */ +export function scannerPerf (page) { + return /** @type {const} */({ + async navigate (url = constants.pages['scanner-perf']) { + await page.goto(url, {waitUntil: 'load'}) + }, + async validateInitialScanPerf (expectedDuration) { + const entries = await performanceEntries(page, 'initial_scanner:init') + + expect(entries).toHaveLength(1) + + // we only care about the first one (for now) + const entry = entries[0] + console.log(`🏎💨 initial scan took: ${Math.round(entry.duration)}ms`) + + expect(entry.duration).toBeLessThan(expectedDuration) + } + }) +} diff --git a/integration-test/pages/scanner-perf.html b/integration-test/pages/scanner-perf.html new file mode 100644 index 000000000..09fdc9bfa --- /dev/null +++ b/integration-test/pages/scanner-perf.html @@ -0,0 +1,30 @@ + + + + + + + Scanner Perf Test + + + +
+
+ +
+
+ + + diff --git a/integration-test/pages/usps_signup.html b/integration-test/pages/usps_signup.html new file mode 100644 index 000000000..80625de49 --- /dev/null +++ b/integration-test/pages/usps_signup.html @@ -0,0 +1,1910 @@ + +
+ + + + + + + + + + + + + + + + + + + +
+
+

Step 1: Choose your language and username

+

Please choose a default language for your USPS account. This can be changed at a later time from your preferences page.

+

Please enter a username which will uniquely identify you with the United States Postal Service.

+ * indicates a required field +
+
+
+ +
+ + + + +
+ + +
+
+ + + + + + + + + + + + + + +
+ +
+
+ +
+
+ +
+
+

Step 2: Enter your security information

+ +

Please create a password for your account. We highly recommend you create a unique password - one that you don't use for other websites.

+ * indicates a required field +
+
+ Pick a Password +
+ + + + + +
+ + +
+ + + + + +
+ + Passwords must be at least 8 characters in length and include at least one uppercase letter, one lowercase letter, and one number. They are case-sensitive and cannot include your username or more than two consecutive identical characters. + + tool tip + + +
+
+
+
+
+
+

Please answer two secret questions. Answers are not case-sensitive. If you forget your password, you will be asked for this information to re-gain access to our site.

+ * indicates a required field +
+
+ Pick Two Security Questions + + + + +
+ + + + + + + + + + + + +
+
+ + + + + + + + + +
+
+ + + + + +
+
+
+   +
+ + + + + + + + +
+
+ + + + + + + + + +
+
+ + + + + + +
+ +
+
+ +
+
+

Step 3: Choose your account type

+

Choose personal account if you are interested in services for your home? i.e. order stamps, renew a MailBox, mail a package, etc.

+

Interested in solutions for your business - home-based, small, medium, or large? Choose business account.

+
+
+
+

Please choose which type of account you would like to create

+ + +
+
+
+ + + + + + +
+
+ +
+
+ + + + + + + + + +
+
+ + + + + + + +
diff --git a/integration-test/tests/bitwarden.macos.spec.js b/integration-test/tests/bitwarden.macos.spec.js new file mode 100644 index 000000000..ea2b87684 --- /dev/null +++ b/integration-test/tests/bitwarden.macos.spec.js @@ -0,0 +1,245 @@ +import {constants} from '../helpers/mocks.js' +import {createAutofillScript, forwardConsoleMessages, mockedCalls} from '../helpers/harness.js' +import {createWebkitMocks, macosContentScopeReplacements} from '../helpers/mocks.webkit.js' +import {createAvailableInputTypes} from '../helpers/utils.js' +import {loginPage, overlayPage} from '../helpers/pages.js' +import {expect, test as base} from '@playwright/test' + +/** + * Tests for various Bitwarden scenarios on macos + */ +const test = base.extend({}) + +const {personalAddress} = constants.fields.email +const password = '123456' + +test.describe('When Bitwarden is the password provider', () => { + test('When the native layer calls to unblock provider UI (on Catalina)', async ({page}) => { + // enable in-terminal exceptions + await forwardConsoleMessages(page) + + await createWebkitMocks() + .withAvailableInputTypes(createAvailableInputTypes({ + credentialsProviderStatus: 'locked' + })) + .withCredentials({ + id: 'provider_locked', + username: '', + password: '', + credentialsProvider: 'bitwarden' + }) + .withCheckCredentialsProviderStatus?.() + .applyTo(page) + + // Load the autofill.js script with replacements + await createAutofillScript() + .replaceAll(macosContentScopeReplacements({ + featureToggles: { + third_party_credentials_provider: true + } + })) + .platform('macos') + .applyTo(page) + + const login = loginPage(page) + await login.navigate() + await login.fieldsContainIcons() + + await login.assertTooltipNotOpen(personalAddress) + + // The call is executed every 2s and we have encoded responses in mocks.webkit.js + await page.waitForTimeout(2000) + + // unlocked with no credentials available + await login.fieldsDoNotContainIcons() + await page.waitForTimeout(2000) + + // unlocked with credentials available + await login.fieldsContainIcons() + await page.waitForTimeout(2000) + + // unlocked with only a password field + await login.onlyPasswordFieldHasIcon() + await page.waitForTimeout(2000) + + // back to being locked + await login.fieldsContainIcons() + }) + + test('When we have Bitwarden credentials', async ({page}) => { + // enable in-terminal exceptions + await forwardConsoleMessages(page) + + await createWebkitMocks() + .withAvailableInputTypes(createAvailableInputTypes()) + .withCredentials({ + id: '01', + username: personalAddress, + password, + credentialsProvider: 'bitwarden' + }) + .applyTo(page) + + // Load the autofill.js script with replacements + await createAutofillScript() + .replaceAll(macosContentScopeReplacements({ + featureToggles: { + third_party_credentials_provider: true + } + })) + .platform('macos') + .applyTo(page) + + const login = loginPage(page) + await login.navigate() + await login.fieldsContainIcons() + + await login.assertTooltipNotOpen(personalAddress) + + await login.assertBitwardenTooltipWorking(personalAddress, password) + }) + + test.describe('When bitwarden is locked', async () => { + test('in overlay', async ({page}) => { + await forwardConsoleMessages(page) + await createWebkitMocks() + .withAvailableInputTypes(createAvailableInputTypes({ + credentialsProviderStatus: 'locked' + })) + .withCredentials({ + id: 'provider_locked', + username: '', + password: '', + credentialsProvider: 'bitwarden' + }) + .withAskToUnlockProvider?.() + .applyTo(page) + + // Pretend we're running in a top-frame scenario + await createAutofillScript() + .replaceAll(macosContentScopeReplacements()) + .replace('isTopFrame', true) + .replace('supportsTopFrame', true) + .platform('macos') + .applyTo(page) + + const overlay = overlayPage(page) + await overlay.navigate() + await overlay.clickButtonWithText('Bitwarden is locked') + await overlay.doesNotCloseParentAfterCall('askToUnlockProvider') + + const autofillCalls = await mockedCalls(page, {names: ['setSize'], minCount: 1}) + expect(autofillCalls.length).toBeGreaterThanOrEqual(1) + }) + + test('when the native layer calls to unblock provider UI (on modern macOS versions)', async ({page}) => { + // enable in-terminal exceptions + await forwardConsoleMessages(page) + + await createWebkitMocks() + .withAvailableInputTypes(createAvailableInputTypes({ + credentialsProviderStatus: 'locked' + })) + .withCredentials({ + id: 'provider_locked', + username: '', + password: '', + credentialsProvider: 'bitwarden' + }) + .applyTo(page) + + // Load the autofill.js script with replacements + await createAutofillScript() + .replaceAll(macosContentScopeReplacements({ + featureToggles: { + third_party_credentials_provider: true + } + })) + .replace('hasModernWebkitAPI', true) + .platform('macos') + .applyTo(page) + + const login = loginPage(page) + await login.navigate() + await login.fieldsContainIcons() + + await login.assertTooltipNotOpen(personalAddress) + + // NOTE: I'm not creating separate test cases because these calls can happen multiple times + // in the page lifecycle with different values, so this is a realistic use case + + // unlocked with no credentials available + await page.evaluate(` + window.providerStatusUpdated({ + status: 'unlocked', + credentials: [], + availableInputTypes: {credentials: {password: false, username: false}} + }) + `) + + await login.fieldsDoNotContainIcons() + + // unlocked with credentials available + await page.evaluate(` + window.providerStatusUpdated({ + status: 'unlocked', + credentials: [ + {id: '3', password: '${password}', username: '${personalAddress}', credentialsProvider: 'bitwarden'} + ], + availableInputTypes: {credentials: {password: true, username: true}} + }) + `) + + await login.fieldsContainIcons() + + // unlocked with only a password field + await page.evaluate(` + window.providerStatusUpdated({ + status: 'unlocked', + credentials: [ + {id: '3', password: '${password}', username: '', credentialsProvider: 'bitwarden'} + ], + availableInputTypes: {credentials: {password: true, username: false}} + }) + `) + + await login.onlyPasswordFieldHasIcon() + }) + + test('without overlay (Catalina)', async ({page}) => { + // enable in-terminal exceptions + await forwardConsoleMessages(page) + + await createWebkitMocks() + .withAvailableInputTypes(createAvailableInputTypes({ + credentialsProviderStatus: 'locked' + })) + .withCredentials({ + id: 'provider_locked', + username: '', + password: '', + credentialsProvider: 'bitwarden' + }) + .withAskToUnlockProvider?.() + .applyTo(page) + + // Load the autofill.js script with replacements + await createAutofillScript() + .replaceAll(macosContentScopeReplacements({ + featureToggles: { + third_party_credentials_provider: true + } + })) + .platform('macos') + .applyTo(page) + + const login = loginPage(page) + await login.navigate() + await login.fieldsContainIcons() + + await login.assertTooltipNotOpen(personalAddress) + + await login.assertBitwardenLockedWorking() + }) + }) +}) diff --git a/integration-test/tests/email-autofill.macos.spec.js b/integration-test/tests/email-autofill.macos.spec.js index d7d089c5b..db382843d 100644 --- a/integration-test/tests/email-autofill.macos.spec.js +++ b/integration-test/tests/email-autofill.macos.spec.js @@ -1,10 +1,10 @@ import { - createAutofillScript, - forwardConsoleMessages, performanceEntries + createAutofillScript, defaultMacosScript, + forwardConsoleMessages } from '../helpers/harness.js' import {test as base, expect} from '@playwright/test' import {constants} from '../helpers/mocks.js' -import {emailAutofillPage, signupPage} from '../helpers/pages.js' +import {emailAutofillPage, scannerPerf, signupPage} from '../helpers/pages.js' import {createWebkitMocks, macosContentScopeReplacements} from '../helpers/mocks.webkit.js' import {createAvailableInputTypes, stripDuckExtension} from '../helpers/utils.js' import {testContext} from '../helpers/test-context.js' @@ -278,19 +278,46 @@ test.describe('macos', () => { ]) }) test.describe('matching performance', () => { - test.skip('matching performance v1', async ({page}) => { + test('real-world form', async ({page}) => { + await forwardConsoleMessages(page) + await createWebkitMocks().applyTo(page) + await defaultMacosScript(page) + + const perfPage = scannerPerf(page) + perfPage.navigate('pages/usps_signup.html') + + perfPage.validateInitialScanPerf(200) + }) + + test('wall of 1000 fields with production settings', async ({page}) => { + await forwardConsoleMessages(page) + await createWebkitMocks().applyTo(page) + await defaultMacosScript(page) + + const perfPage = scannerPerf(page) + perfPage.navigate() + + // In production, we expect autofill to bail on such a page + perfPage.validateInitialScanPerf(2) + }) + + test('wall of 1000 fields with extreme settings', async ({page}) => { await forwardConsoleMessages(page) await createWebkitMocks().applyTo(page) await createAutofillScript() .replaceAll(macosContentScopeReplacements()) .platform('macos') + // Up the failsafe threshold to run the test + .withConstants({ + MAX_INPUTS_PER_PAGE: 2000, + MAX_INPUTS_PER_FORM: 2000 + }) .applyTo(page) - await page.goto('src/Form/test-cases/usps_signup.html') - const r = await performanceEntries(page, 'scanner:init') - for (let performanceEntry of r) { - console.log(performanceEntry.duration) - } + const perfPage = scannerPerf(page) + perfPage.navigate() + + perfPage.validateInitialScanPerf(300) }) }) }) diff --git a/integration-test/tests/login-form.macos.spec.js b/integration-test/tests/login-form.macos.spec.js index faa3b8c66..55000e509 100644 --- a/integration-test/tests/login-form.macos.spec.js +++ b/integration-test/tests/login-form.macos.spec.js @@ -1,8 +1,8 @@ import {constants} from '../helpers/mocks.js' import {createWebkitMocks, macosContentScopeReplacements} from '../helpers/mocks.webkit.js' -import {createAutofillScript, forwardConsoleMessages, mockedCalls} from '../helpers/harness.js' +import {createAutofillScript, forwardConsoleMessages} from '../helpers/harness.js' import {loginPage, overlayPage} from '../helpers/pages.js' -import {expect, test as base} from '@playwright/test' +import {test as base} from '@playwright/test' import {createAvailableInputTypes} from '../helpers/utils.js' /** @@ -329,237 +329,6 @@ test.describe('Auto-fill a login form on macOS', () => { }) }) - test.describe('When Bitwarden is the password provider', () => { - test('When we have Bitwarden credentials', async ({page}) => { - // enable in-terminal exceptions - await forwardConsoleMessages(page) - - await createWebkitMocks() - .withAvailableInputTypes(createAvailableInputTypes()) - .withCredentials({ - id: '01', - username: personalAddress, - password, - credentialsProvider: 'bitwarden' - }) - .applyTo(page) - - // Load the autofill.js script with replacements - await createAutofillScript() - .replaceAll(macosContentScopeReplacements({ - featureToggles: { - third_party_credentials_provider: true - } - })) - .platform('macos') - .applyTo(page) - - const login = loginPage(page) - await login.navigate() - await login.fieldsContainIcons() - - await login.assertTooltipNotOpen(personalAddress) - - await login.assertBitwardenTooltipWorking(personalAddress, password) - }) - - test.describe('When bitwarden is locked', async () => { - test('in overlay', async ({page}) => { - await forwardConsoleMessages(page) - await createWebkitMocks() - .withAvailableInputTypes(createAvailableInputTypes({ - credentialsProviderStatus: 'locked' - })) - .withCredentials({ - id: 'provider_locked', - username: '', - password: '', - credentialsProvider: 'bitwarden' - }) - .withAskToUnlockProvider?.() - .applyTo(page) - - // Pretend we're running in a top-frame scenario - await createAutofillScript() - .replaceAll(macosContentScopeReplacements()) - .replace('isTopFrame', true) - .replace('supportsTopFrame', true) - .platform('macos') - .applyTo(page) - - const overlay = overlayPage(page) - await overlay.navigate() - await overlay.clickButtonWithText('Bitwarden is locked') - await overlay.doesNotCloseParentAfterCall('askToUnlockProvider') - - const autofillCalls = await mockedCalls(page, {names: ['setSize'], minCount: 1}) - expect(autofillCalls.length).toBeGreaterThanOrEqual(1) - }) - - test('when the native layer calls to unblock provider UI (on modern macOS versions)', async ({page}) => { - // enable in-terminal exceptions - await forwardConsoleMessages(page) - - await createWebkitMocks() - .withAvailableInputTypes(createAvailableInputTypes({ - credentialsProviderStatus: 'locked' - })) - .withCredentials({ - id: 'provider_locked', - username: '', - password: '', - credentialsProvider: 'bitwarden' - }) - .applyTo(page) - - // Load the autofill.js script with replacements - await createAutofillScript() - .replaceAll(macosContentScopeReplacements({ - featureToggles: { - third_party_credentials_provider: true - } - })) - .replace('hasModernWebkitAPI', true) - .platform('macos') - .applyTo(page) - - const login = loginPage(page) - await login.navigate() - await login.fieldsContainIcons() - - await login.assertTooltipNotOpen(personalAddress) - - // NOTE: I'm not creating separate test cases because these calls can happen multiple times - // in the page lifecycle with different values, so this is a realistic use case - - // unlocked with no credentials available - await page.evaluate(` - window.providerStatusUpdated({ - status: 'unlocked', - credentials: [], - availableInputTypes: {credentials: {password: false, username: false}} - }) - `) - - await login.fieldsDoNotContainIcons() - - // unlocked with credentials available - await page.evaluate(` - window.providerStatusUpdated({ - status: 'unlocked', - credentials: [ - {id: '3', password: '${password}', username: '${personalAddress}', credentialsProvider: 'bitwarden'} - ], - availableInputTypes: {credentials: {password: true, username: true}} - }) - `) - - await login.fieldsContainIcons() - - // unlocked with only a password field - await page.evaluate(` - window.providerStatusUpdated({ - status: 'unlocked', - credentials: [ - {id: '3', password: '${password}', username: '', credentialsProvider: 'bitwarden'} - ], - availableInputTypes: {credentials: {password: true, username: false}} - }) - `) - - await login.onlyPasswordFieldHasIcon() - }) - - test('without overlay (Catalina)', async ({page}) => { - // enable in-terminal exceptions - await forwardConsoleMessages(page) - - await createWebkitMocks() - .withAvailableInputTypes(createAvailableInputTypes({ - credentialsProviderStatus: 'locked' - })) - .withCredentials({ - id: 'provider_locked', - username: '', - password: '', - credentialsProvider: 'bitwarden' - }) - .withAskToUnlockProvider?.() - .applyTo(page) - - // Load the autofill.js script with replacements - await createAutofillScript() - .replaceAll(macosContentScopeReplacements({ - featureToggles: { - third_party_credentials_provider: true - } - })) - .platform('macos') - .applyTo(page) - - const login = loginPage(page) - await login.navigate() - await login.fieldsContainIcons() - - await login.assertTooltipNotOpen(personalAddress) - - await login.assertBitwardenLockedWorking() - }) - - test('when the native layer calls to unblock provider UI (on Catalina)', async ({page}) => { - // enable in-terminal exceptions - await forwardConsoleMessages(page) - - await createWebkitMocks() - .withAvailableInputTypes(createAvailableInputTypes({ - credentialsProviderStatus: 'locked' - })) - .withCredentials({ - id: 'provider_locked', - username: '', - password: '', - credentialsProvider: 'bitwarden' - }) - .withCheckCredentialsProviderStatus?.() - .applyTo(page) - - // Load the autofill.js script with replacements - await createAutofillScript() - .replaceAll(macosContentScopeReplacements({ - featureToggles: { - third_party_credentials_provider: true - } - })) - .platform('macos') - .applyTo(page) - - const login = loginPage(page) - await login.navigate() - await login.fieldsContainIcons() - - await login.assertTooltipNotOpen(personalAddress) - - // The call is executed every 2s and we have encoded responses in mocks.webkit.js - await page.waitForTimeout(2000) - - // unlocked with no credentials available - await login.fieldsDoNotContainIcons() - await page.waitForTimeout(2000) - - // unlocked with credentials available - await login.fieldsContainIcons() - await page.waitForTimeout(2000) - - // unlocked with only a password field - await login.onlyPasswordFieldHasIcon() - await page.waitForTimeout(2000) - - // back to being locked - await login.fieldsContainIcons() - }) - }) - }) - test.describe('The manage button', () => { const testCases = [ { diff --git a/playwright.config.js b/playwright.config.js index 6e3e778c3..e132e4dc5 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -22,6 +22,7 @@ const config = { */ timeout: 5000 }, + fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ diff --git a/src/Form/matching.js b/src/Form/matching.js index 9e029ba3d..8d1fd348b 100644 --- a/src/Form/matching.js +++ b/src/Form/matching.js @@ -242,8 +242,8 @@ class Matching { if (this.subtypeFromMatchers('unknown', input)) return 'unknown' - // // For CC forms we run aggressive matches, so we want to make sure we only - // // run them on actual CC forms to avoid false positives and expensive loops + // For CC forms we run aggressive matches, so we want to make sure we only + // run them on actual CC forms to avoid false positives and expensive loops if (opts.isCCForm) { const subtype = this.subtypeFromMatchers('cc', input) if (subtype && isValidCreditCardSubtype(subtype)) { diff --git a/swift-package/Resources/assets/autofill-debug.js b/swift-package/Resources/assets/autofill-debug.js index 9ccabd40e..ef017be86 100644 --- a/swift-package/Resources/assets/autofill-debug.js +++ b/swift-package/Resources/assets/autofill-debug.js @@ -13656,8 +13656,8 @@ class Matching { } this.setActiveElementStrings(input, formEl); - if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // // For CC forms we run aggressive matches, so we want to make sure we only - // // run them on actual CC forms to avoid false positives and expensive loops + if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // For CC forms we run aggressive matches, so we want to make sure we only + // run them on actual CC forms to avoid false positives and expensive loops if (opts.isCCForm) { const subtype = this.subtypeFromMatchers('cc', input); diff --git a/swift-package/Resources/assets/autofill.js b/swift-package/Resources/assets/autofill.js index 36465880d..f4601f47b 100644 --- a/swift-package/Resources/assets/autofill.js +++ b/swift-package/Resources/assets/autofill.js @@ -9980,8 +9980,8 @@ class Matching { } this.setActiveElementStrings(input, formEl); - if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // // For CC forms we run aggressive matches, so we want to make sure we only - // // run them on actual CC forms to avoid false positives and expensive loops + if (this.subtypeFromMatchers('unknown', input)) return 'unknown'; // For CC forms we run aggressive matches, so we want to make sure we only + // run them on actual CC forms to avoid false positives and expensive loops if (opts.isCCForm) { const subtype = this.subtypeFromMatchers('cc', input);