Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New batch of fixes + integration test improvements #489

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referencing either the local path or the privacy test pages path. I will migrate more and more over time.

'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')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've switched this to use the locator with expect so that playwright automatically pierces the shadow tree and waits for the attribute to be set. Otherwise, I'd have to implement something custom for waitForFunction. This also seems much cleaner.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌


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

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('dax@example.com')
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
Loading