diff --git a/src/liquid/components/ld-button/ld-button.tsx b/src/liquid/components/ld-button/ld-button.tsx
index 6fc512cbfe..f68c59b557 100644
--- a/src/liquid/components/ld-button/ld-button.tsx
+++ b/src/liquid/components/ld-button/ld-button.tsx
@@ -76,8 +76,19 @@ export class LdButton implements InnerFocusable {
})
}
+ private clickFakeButton(
+ form: HTMLFormElement,
+ buttonType: 'submit' | 'reset'
+ ) {
+ const btnFake = document.createElement('button')
+ btnFake.type = buttonType
+ btnFake.style.display = 'none'
+ form.appendChild(btnFake)
+ btnFake.click()
+ btnFake.remove()
+ }
+
private handleClick = (event: MouseEvent) => {
- console.log(event.target)
const ariaDisabled = this.button.getAttribute('aria-disabled')
if (this.disabled || (ariaDisabled && ariaDisabled !== 'false')) {
@@ -85,6 +96,20 @@ export class LdButton implements InnerFocusable {
event.stopImmediatePropagation()
return
}
+
+ if (!this.href) {
+ const form = this.el.closest('form')
+ if (form) {
+ switch (this.el.getAttribute('type')) {
+ case 'reset':
+ this.clickFakeButton(form, 'reset')
+ break
+ case 'submit':
+ default:
+ this.clickFakeButton(form, 'submit')
+ }
+ }
+ }
}
componentWillLoad() {
diff --git a/src/liquid/components/ld-button/test/ld-button.e2e.ts b/src/liquid/components/ld-button/test/ld-button.e2e.ts
index 01f040ade8..7422a737ff 100644
--- a/src/liquid/components/ld-button/test/ld-button.e2e.ts
+++ b/src/liquid/components/ld-button/test/ld-button.e2e.ts
@@ -4,14 +4,6 @@ import { LdButton } from '../ld-button'
jest.useRealTimers()
-const themes = [
- 'ocean',
- // 'bubblegum',
- // 'shake',
- // 'solvent',
- 'tea',
-]
-
const modes = [
'',
'highlight',
@@ -35,318 +27,300 @@ const allowableMismatchedRatio = 0.02
describe('ld-button', () => {
for (const mode of modes) {
- const modeStr = mode ? ` ${mode}` : ''
- describe(`themed${modeStr}`, () => {
- for (const theme of themes) {
- // Themed
- it(`default theme-${theme}${modeStr}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.hover('ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ const modeStr = mode ? `mode ${mode}` : 'mode none'
+ describe(modeStr, () => {
+ it(`default ${modeStr}`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`hover`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.hover('ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`focus`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`active`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Disabled
- it(`disabled theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`disabled hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.hover('ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`disabled focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`disabled active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Disabled
+ it(`disabled`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`disabled hover`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.hover('ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`disabled focus`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`disabled active`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Aria-disabled
- it(`aria-disabled theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`aria-disabled hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.hover('ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`aria-disabled focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`aria-disabled active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Aria-disabled
+ it(`aria-disabled`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`aria-disabled hover`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.hover('ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`aria-disabled focus`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`aria-disabled active`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Progress button
- it(`progress button theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Progress button
+ it(`progress button`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- it(`progress button secondary theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ it(`progress button secondary`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- it(`progress button ghost theme-${theme}`, async () => {
- const page = await getPageWithContent(
- `Text`,
- theme
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ it(`progress button ghost`, async () => {
+ const page = await getPageWithContent(
+ `Text`
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Themed CSS component
- const modeModifier = mode ? ` ld-button--${mode}` : ''
- it(`css component default theme-${theme}${modeStr}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.hover('.ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // CSS component
+ const modeModifier = mode ? ` ld-button--${mode}` : ''
+ it(`css component default ${modeStr}`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component hover`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.hover('.ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component focus`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component active`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Disabled CSS component
- it(`css component disabled theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component disabled hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.hover('.ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component disabled focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component disabled active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Disabled CSS component
+ it(`css component disabled`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component disabled hover`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.hover('.ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component disabled focus`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component disabled active`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Aria-disabled CSS component
- it(`css component aria-disabled theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component aria-disabled hover theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.hover('.ld-button')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component aria-disabled focus theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- it(`css component aria-disabled active theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- [LdButton, LdIcon]
- )
- await page.keyboard.press('Tab')
- await page.keyboard.down('Space')
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Aria-disabled CSS component
+ it(`css component aria-disabled`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component aria-disabled hover`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.hover('.ld-button')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component aria-disabled focus`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
+ it(`css component aria-disabled active`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ [LdButton, LdIcon]
+ )
+ await page.keyboard.press('Tab')
+ await page.keyboard.down('Space')
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- // Progress button CSS component
- it(`css component progress button theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- LdButton
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ // Progress button CSS component
+ it(`css component progress button`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ LdButton
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- it(`css component progress button secondary theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- LdButton
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
+ it(`css component progress button secondary`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ LdButton
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
- it(`css component progress button ghost theme-${theme}`, async () => {
- const page = await getPageWithContent(
- ``,
- theme,
- LdButton
- )
- const results = await page.compareScreenshot()
- expect(results).toMatchScreenshot({ allowableMismatchedRatio })
- })
- }
+ it(`css component progress button ghost`, async () => {
+ const page = await getPageWithContent(
+ ``,
+ undefined,
+ LdButton
+ )
+ const results = await page.compareScreenshot()
+ expect(results).toMatchScreenshot({ allowableMismatchedRatio })
+ })
})
}
@@ -455,4 +429,21 @@ describe('ld-button', () => {
expect(results).toMatchScreenshot({ allowableMismatchedRatio })
})
})
+
+ describe('implicit form submission', () => {
+ it('submits form implicitly', async () => {
+ const page = await getPageWithContent(
+ `
`
+ )
+ const form = await page.find('form')
+ expect(form).not.toBeNull()
+ const formSubmitSpy = await form.spyOnEvent('submit')
+
+ // Using ldButton.click here leads to Error: Node is either not visible or not an HTMLElement
+ await page.evaluate(() => document.querySelector('ld-button').click())
+ page.waitForChanges()
+
+ expect(formSubmitSpy).toHaveReceivedEvent()
+ })
+ })
})
diff --git a/src/liquid/components/ld-button/test/ld-button.spec.ts b/src/liquid/components/ld-button/test/ld-button.spec.ts
index 479f559177..0a94011825 100644
--- a/src/liquid/components/ld-button/test/ld-button.spec.ts
+++ b/src/liquid/components/ld-button/test/ld-button.spec.ts
@@ -176,4 +176,87 @@ describe('ld-button', () => {
expect(button.focus).toHaveBeenCalled()
})
+
+ describe('implicit form submission', () => {
+ beforeAll(() => {
+ // Mock clickFakeButton (actual implementation tested in e2e test).
+ jest
+ .spyOn(
+ (LdButton.prototype as unknown) as { clickFakeButton },
+ 'clickFakeButton'
+ )
+ .mockImplementation(
+ (form: HTMLFormElement, buttonType: 'submit' | 'reset') => {
+ form.dispatchEvent(new Event(buttonType))
+ }
+ )
+ })
+
+ afterAll(() => {
+ jest.restoreAllMocks()
+ })
+
+ it('submits a form implicitly', async () => {
+ const page = await newSpecPage({
+ components: [LdButton],
+ html: ``,
+ })
+ const form = page.body.querySelector('form')
+
+ const ldButton = page.body.querySelector('ld-button')
+ const submitHandler = jest.fn()
+ const resetHandler = jest.fn()
+
+ form.addEventListener('submit', submitHandler)
+ form.addEventListener('reset', resetHandler)
+ ldButton.dispatchEvent(
+ new MouseEvent('click', { bubbles: true, cancelable: true })
+ )
+
+ expect(submitHandler).toHaveBeenCalled()
+ expect(resetHandler).not.toHaveBeenCalled()
+ })
+
+ it('does not submit a form as an anchor', async () => {
+ const page = await newSpecPage({
+ components: [LdButton],
+ html: ``,
+ })
+ const form = page.body.querySelector('form')
+
+ const ldButton = page.body.querySelector('ld-button')
+ const submitHandler = jest.fn()
+ const resetHandler = jest.fn()
+
+ form.addEventListener('submit', submitHandler)
+ form.addEventListener('reset', resetHandler)
+ ldButton.dispatchEvent(
+ new MouseEvent('click', { bubbles: true, cancelable: true })
+ )
+
+ expect(submitHandler).not.toHaveBeenCalled()
+ expect(resetHandler).not.toHaveBeenCalled()
+ })
+
+ it('resets a form', async () => {
+ const page = await newSpecPage({
+ components: [LdButton],
+ html: ``,
+ })
+ const form = page.body.querySelector('form')
+
+ const ldButton = page.body.querySelector('ld-button')
+ const submitHandler = jest.fn()
+ const resetHandler = jest.fn()
+
+ form.addEventListener('submit', submitHandler)
+ form.addEventListener('reset', resetHandler)
+ ldButton.dispatchEvent(
+ new MouseEvent('click', { bubbles: true, cancelable: true })
+ )
+
+ expect(submitHandler).not.toHaveBeenCalled()
+ expect(resetHandler).toHaveBeenCalled()
+ })
+ })
})