Skip to content

Commit

Permalink
New batch of fixes + integration test improvements (#489)
Browse files Browse the repository at this point in the history
* Form bug fixes

Signed-off-by: Emanuele Feliziani <[email protected]>

* Update integration tests

Signed-off-by: Emanuele Feliziani <[email protected]>

---------

Signed-off-by: Emanuele Feliziani <[email protected]>
  • Loading branch information
GioSensation authored Jan 30, 2024
1 parent d64a4c6 commit 03d3e3a
Show file tree
Hide file tree
Showing 21 changed files with 1,614 additions and 136 deletions.
11 changes: 6 additions & 5 deletions dist/autofill-debug.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions dist/autofill.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 20 additions & 17 deletions integration-test/helpers/mocks.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
const localPagesPrefix = 'integration-test/pages'
const privacyTestPagesPrefix = 'node_modules/@duckduckgo/privacy-test-pages/autofill'
/**
* Try to use this a place to store re-used values across the integration tests.
*/
export const constants = {
pages: {
'overlay': 'pages/overlay.html',
'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',
'perf-huge-regex': 'pages/perf-huge-regex.html',
'iframeContainer': 'pages/iframe-container.html',
'signup': 'pages/signup.html',
'mutatingForm': 'pages/mutating-form.html',
'passwordUpdate': 'pages/password-update.html',
'login': 'pages/login.html',
'loginWithPoorForm': 'pages/login-poor-form.html',
'loginWithText': 'pages/login-with-text.html',
'loginWithFormInModal': 'pages/login-in-modal.html',
'signupWithFormInModal': 'pages/signup-in-modal.html',
'loginCovered': 'pages/login-covered.html',
'loginMultistep': 'pages/login-multistep.html'
'overlay': `${localPagesPrefix}/overlay.html`,
'email-autofill': `${localPagesPrefix}/email-autofill.html`,
'emailAtBottom': `${localPagesPrefix}/email-at-bottom.html`,
'emailAtTopLeft': `${localPagesPrefix}/email-at-top-left.html`,
'scanner-perf': `${localPagesPrefix}/scanner-perf.html`,
'perf-huge-regex': `${localPagesPrefix}/perf-huge-regex.html`,
'iframeContainer': `${localPagesPrefix}/iframe-container.html`,
'signup': `${localPagesPrefix}/signup.html`,
'mutatingForm': `${localPagesPrefix}/mutating-form.html`,
'passwordUpdate': `${privacyTestPagesPrefix}/password-update.html`,
'login': `${localPagesPrefix}/login.html`,
'loginWithPoorForm': `${localPagesPrefix}/login-poor-form.html`,
'loginWithText': `${localPagesPrefix}/login-with-text.html`,
'loginWithFormInModal': `${privacyTestPagesPrefix}/autoprompt/2-form-in-modal.html`,
'signupWithFormInModal': `${localPagesPrefix}/signup-in-modal.html`,
'loginCovered': `${localPagesPrefix}/login-covered.html`,
'loginMultistep': `${localPagesPrefix}/login-multistep.html`,
'shadowDom': `${privacyTestPagesPrefix}/shadow-dom.html`
},
fields: {
email: {
Expand Down
2 changes: 1 addition & 1 deletion integration-test/helpers/pages/emailAutofillPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function emailAutofillPage (page) {
async navigate (domain) {
const emailAutofillPageName = constants.pages['email-autofill']
if (domain) {
const pagePath = `integration-test/${emailAutofillPageName}`
const pagePath = `/${emailAutofillPageName}`
await page.goto(new URL(pagePath, domain).href)
} else {
await page.goto(emailAutofillPageName)
Expand Down
19 changes: 14 additions & 5 deletions integration-test/helpers/pages/genericPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@ import {constants} from '../mocks.js'
export function genericPage (page) {
class GenericPage {
async passwordFieldShowsFillKey (selector = '#password') {
// don't make assertions until the element is both found + has a none-empty 'style' attribute
await page.waitForFunction(selector => Boolean(document.querySelector(selector)?.getAttribute('style')), selector)
// don't make assertions until the element has been scanned
const field = page.locator(selector)
await expect(field).toHaveAttribute('data-ddg-inputtype')

const passwordStyle = await page.locator(selector).getAttribute('style')
expect(passwordStyle).toContain(constants.iconMatchers.keyFill)

Check failure on line 18 in integration-test/helpers/pages/genericPage.js

View workflow job for this annotation

GitHub Actions / test

[macos] › mutating-form.macos.spec.js:24:5 › Mutating form page › works fine on macOS

1) [macos] › mutating-form.macos.spec.js:24:5 › Mutating form page › works fine on macOS ───────── Error: expect(received).toContain(expected) // indexOf Expected substring: "data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8cGF0aCBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNS4zMzQgNi42NjdhMiAyIDAgMSAwIDAgNCAyIDIgMCAwIDAgMC00Wm0tLjY2NyAyYS42NjcuNjY3IDAgMSAxIDEuMzMzIDAgLjY2Ny42NjcgMCAwIDEtMS4zMzMgMFoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgogICAgPHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTQuNjY3IDRhNS4zMzMgNS4zMzMgMCAwIDAtNS4xODggNi41NzhsLTUuMjg0IDUuMjg0YS42NjcuNjY3IDAgMCAwLS4xOTUuNDcxdjNjMCAuMzY5LjI5OC42NjcuNjY3LjY2N2gyLjY2NmMuNzM3IDAgMS4zMzQtLjU5NyAxLjMzNC0xLjMzM1YxOGguNjY2Yy43MzcgMCAxLjMzNC0uNTk3IDEuMzM0LTEuMzMzdi0xLjMzNEgxMmMuMTc3IDAgLjM0Ni0uMDcuNDcxLS4xOTVsLjY4OC0uNjg4QTUuMzMzIDUuMzMzIDAgMSAwIDE0LjY2NyA0Wm0tNCA1LjMzM2E0IDQgMCAxIDEgMi41NTUgMy43MzIuNjY3LjY2NyAwIDAgMC0uNzEzLjE1bC0uNzg1Ljc4NUgxMGEuNjY3LjY2NyAwIDAgMC0uNjY3LjY2N3YySDhhLjY2Ny42NjcgMCAwIDAtLjY2Ny42NjZ2MS4zMzRoLTJ2LTIuMDU4bDUuMzY1LTUuMzY0YS42NjcuNjY3IDAgMCAwIC4xNjMtLjY3NyAzLjk5NiAzLjk5NiAwIDAgMS0uMTk0LTEuMjM1WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+Cjwvc3ZnPgo=" Received string: "background-size: auto 100% !important; background-position: right center !important; background-repeat: no-repeat !important; background-origin: content-box !important; background-image: url(\"data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8cGF0aCBmaWxsPSIjMDAwIiBkPSJNOC4wNDcgNC42MjVDNy45MzcgNC4xMjUgNy44NjIgNCA3LjUgNGMtLjM2MiAwLS40MzguMTI1LS41NDcuNjI1LS4wNjguMzEtLjE3NyAxLjMzOC0uMjUxIDIuMDc3LS43MzguMDc0LTEuNzY3LjE4My0yLjA3Ny4yNTEtLjUuMTEtLjYyNS4xODQtLjYyNS41NDcgMCAuMzYyLjEyNS40MzcuNjI1LjU0Ny4zMS4wNjcgMS4zMzYuMTc3IDIuMDc0LjI1LjA3My43NjcuMTg1IDEuODQyLjI1NCAyLjA3OC4xMS4zNzUuMTg1LjYyNS41NDcuNjI1LjM2MiAwIC40MzgtLjEyNS41NDctLjYyNS4wNjgtLjMxLjE3Ny0xLjMzNi4yNS0yLjA3NC43NjctLjA3MyAxLjg0Mi0uMTg1IDIuMDc4LS4yNTQuMzc1LS4xMS42MjUtLjE4NS42MjUtLjU0NyAwLS4zNjMtLjEyNS0uNDM4LS42MjUtLjU0Ny0uMzEtLjA2OC0xLjMzOS0uMTc3LTIuMDc3LS4yNTEtLjA3NC0uNzM5LS4xODMtMS43NjctLjI1MS0yLjA3N1oiLz4KICAgIDxwYXRoIGZpbGw9IiMwMDAiIGQ9Ik0xNC42ODEgNS4xOTljLS43NjYgMC0xLjQ4Mi4yMS0yLjA5My41NzhhLjYzNi42MzYgMCAwIDEtLjY1NS0xLjA5IDUuMzQgNS4zNCAwIDEgMSAxLjMwMiA5LjcyMmwtLjc3NS43NzZhLjYzNi42MzYgMCAwIDEtLjQ1LjE4NmgtMS4zOTh2MS42NWMwIC40OTMtLjQuODkzLS44OTMuODkzSDguNTc4djEuMTQxYzAgLjQ5NC0uNC44OTMtLjg5NC44OTNINC42MzZBLjYzNi42MzYgMCAwIDEgNCAxOS4zMTNWMTYuMjZjMC0uMTY5LjA2Ny0uMzMuMTg2LS40NWw1LjU2Mi01LjU2MmEuNjM2LjYzNiAwIDEgMSAuOS45bC01LjM3NiA1LjM3NXYyLjE1M2gyLjAzNHYtMS4zOTljMC0uMzUuMjg1LS42MzYuNjM2LS42MzZIOS4zNHYtMS45MDdjMC0uMzUxLjI4NC0uNjM2LjYzNS0uNjM2aDEuNzcxbC44NjQtLjg2M2EuNjM2LjYzNiAwIDAgMSAuNjY4LS4xNDcgNC4wNjkgNC4wNjkgMCAxIDAgMS40MDItNy44OVoiLz4KICAgIDxwYXRoIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTEzLjYyNSA4LjQ5OWExLjg3NSAxLjg3NSAwIDEgMSAzLjc1IDAgMS44NzUgMS44NzUgMCAwIDEtMy43NSAwWm0xLjg3NS0uNjI1YS42MjUuNjI1IDAgMSAwIDAgMS4yNS42MjUuNjI1IDAgMCAwIDAtMS4yNVoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPgogICAgPHBhdGggZmlsbD0iIzAwMCIgZD0iTTQuNjI1IDEyLjEyNWEuNjI1LjYyNSAwIDEgMCAwLTEuMjUuNjI1LjYyNSAwIDAgMCAwIDEuMjVaIi8+Cjwvc3ZnPgo=\") !important; transition: background !important;" at ../helpers/pages/genericPage.js:18 16 | 17 | const passwordStyle = await page.locator(selector).getAttribute('style') > 18 | expect(passwordStyle).toContain(constants.iconMatchers.keyFill) | ^ 19 | } 20 | 21 | async passwordFieldShowsGenKey (selector = '#password') { at GenericPage.passwordFieldShowsFillKey (/home/runner/work/duckduckgo-autofill/duckduckgo-autofill/integration-test/helpers/pages/genericPage.js:18:35) at /home/runner/work/duckduckgo-autofill/duckduckgo-autofill/integration-test/tests/mutating-form.macos.spec.js:47:9
}

async passwordFieldShowsGenKey (selector = '#password') {
// don't make assertions until the element is both found + has a none-empty 'style' attribute
await page.waitForFunction(selector => Boolean(document.querySelector(selector)?.getAttribute('style')), selector)
// don't make assertions until the element has been scanned
const field = page.locator(selector)
await expect(field).toHaveAttribute('data-ddg-inputtype')

const passwordStyle = await page.locator(selector).getAttribute('style')
expect(passwordStyle).toContain(constants.iconMatchers.keyGen)
}
Expand All @@ -28,9 +32,14 @@ export function genericPage (page) {
expect(passwordStyle || '').not.toContain('data:image/svg+xml;base64,')
}

async clickThePasswordField (selector = '#password') {
const input = page.locator(selector)
await input.click({force: true})
}

async selectGeneratedPassword (selector = '#password') {
const input = page.locator(selector)
await input.click()
await input.click({force: true})

const passwordBtn = page.locator('button:has-text("Generated password")')
await expect(passwordBtn).toContainText('Password will be saved for this website')
Expand Down
2 changes: 1 addition & 1 deletion integration-test/helpers/pages/incontextSignupPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function incontextSignupPage (page, {platform} = {platform: 'extension'})
*/
async navigate (domain, to = 'iframeContainer') {
const pageName = constants.pages[to]
const pagePath = `integration-test/${pageName}`
const pagePath = `/${pageName}`
await page.goto(new URL(pagePath, domain).href)
}

Expand Down
37 changes: 37 additions & 0 deletions integration-test/helpers/pages/shadowDomPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {constants} from '../mocks.js'

import {genericPage} from './genericPage.js'

/**
* @param {import("@playwright/test").Page} page
*/
export function shadowDomPage (page) {
class ShadowDomPage {
async navigate () {
await page.goto(constants.pages['shadowDom'])
}

async showTheForm () {
const toggleBtn = page.locator(`button:has-text("Click here to sign up")`)
await toggleBtn.click()
}

async clickThePasswordField () {
return genericPage(page).clickThePasswordField()
}

passwordHasNoIcon () {
return genericPage(page).passwordHasNoIcon()
}

passwordFieldShowsGenKey () {
return genericPage(page).passwordFieldShowsGenKey()
}

selectGeneratedPassword () {
return genericPage(page).selectGeneratedPassword()
}
}

return new ShadowDomPage()
}
1 change: 0 additions & 1 deletion integration-test/tests/email-autofill.macos.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ test.describe('macos', () => {
autogenerated: true,
username: constants.fields.email.privateAddress0
})
await page.pause()

await signup.changeEmailFieldTo('[email protected]')
await signup.enterPassword('abcd')
Expand Down
6 changes: 6 additions & 0 deletions integration-test/tests/login-form.macos.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {test as base} from '@playwright/test'
import {createAvailableInputTypes} from '../helpers/utils.js'
import {loginPage} from '../helpers/pages/loginPage.js'
import {overlayPage} from '../helpers/pages/overlayPage.js'
import {genericPage} from '../helpers/pages/genericPage.js'

/**
* Tests for various auto-fill scenarios on macos
Expand Down Expand Up @@ -261,6 +262,8 @@ test.describe('Auto-fill a login form on macOS', () => {
await login.assertDialogClose()
await login.openDialog()

await genericPage(page).passwordFieldShowsFillKey()

await login.selectFirstCredential(personalAddress)
await login.assertFirstCredential(personalAddress, password)
await login.assertFormNotSubmittedAutomatically()
Expand Down Expand Up @@ -322,6 +325,9 @@ test.describe('Auto-fill a login form on macOS', () => {
test('Escape key should only close the dialog if our tooltip is not showing', async ({page}) => {
const login = await createLoginFormInModalPage(page)
await login.openDialog()

await genericPage(page).passwordFieldShowsFillKey()

await login.clickIntoUsernameInput()
await login.hitEscapeKey()
await login.assertDialogOpen()
Expand Down
53 changes: 53 additions & 0 deletions integration-test/tests/shadow-dom.macos.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {createAutofillScript, forwardConsoleMessages} from '../helpers/harness.js'
import {createWebkitMocks, macosContentScopeReplacements} from '../helpers/mocks.webkit.js'
import {test as base} from '@playwright/test'
import {createAvailableInputTypes} from '../helpers/utils.js'
import {constants} from '../helpers/mocks.js'
import {shadowDomPage} from '../helpers/pages/shadowDomPage.js'

/**
* Tests for various auto-fill scenarios on macos
*/
const test = base.extend({})

const {personalAddress} = constants.fields.email
const password = '123456'

test.describe('Page with form in shadow DOM', () => {
async function applyScript (page) {
await createAutofillScript()
.replaceAll(macosContentScopeReplacements())
.platform('macos')
.applyTo(page)
}

test('form is scanned on click', async ({page}) => {
// enable in-terminal exceptions
await forwardConsoleMessages(page)
await createWebkitMocks()
.withAvailableInputTypes(createAvailableInputTypes())
.withCredentials({
id: '01',
username: personalAddress,
password,
credentialsProvider: 'duckduckgo'
})
.applyTo(page)

// Load the autofill.js script with replacements
await await applyScript(page)

const shadowDom = shadowDomPage(page)
await shadowDom.navigate()

await shadowDom.showTheForm()

await shadowDom.passwordHasNoIcon()

await shadowDom.clickThePasswordField()

await shadowDom.passwordFieldShowsGenKey()

await shadowDom.selectGeneratedPassword()
})
})
Loading

0 comments on commit 03d3e3a

Please sign in to comment.