Skip to content
This repository has been archived by the owner on Nov 6, 2023. It is now read-only.

Commit

Permalink
Simplify + harden cy.fill of Combobox. (#117)
Browse files Browse the repository at this point in the history
* Simplify + harden cy.fill of Combobox.
Switch to "clear then choose" heuristic, identical to Select.
Add robustness tests.

* Remove extraneous .focus() from fill!

* Use Combobox automation hooks with clear
  • Loading branch information
xeger authored Feb 24, 2023
1 parent e72fb77 commit 106b458
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 13 deletions.
68 changes: 68 additions & 0 deletions cypress/component/commands/clear.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,74 @@ describe('cy.clear', () => {
cy.component(comp.Combobox, 'some label').clear();
cy.get('[data-testid=combobox-menu]').should('not.be.visible');
});

it('cooperates with fill', () => {
let selected = 'alpha';

cy.mount(
<Testbed
initialValue={selected}
onChange={(v) => {
selected = v;
}}
/>
);

cy.component(comp.Combobox, 'some label').fill('alpha');
eventually(() => selected === 'alpha');
cy.component(comp.Combobox, 'some label').clear();
eventually(() => selected === undefined);
});

context('with test-automation hooks', () => {
function FutureTestbed({ clearable = true, onClear, onToggle }) {
return (
<FormLabelGroup label="some label">
<div data-testid="combobox-dropdown" class="combobox dropdown">
<div aria-haspopup="true" aria-expanded="false">
<div class="input-group">
<input data-testid="combobox-input" class="form-control" placeholder="Select..." />
<button disabled={!clearable} type="button" onClick={onClear} data-testid="combobox-clear" title="Clear value" class="bg-transparent border-0 font-weight-bold px-0 btn btn-secondary disabled" style={{ opacity: 0 }}>×</button>
<button type="button" onClick={onToggle} data-testid="combobox-caret" class="bg-transparent border-0 pl-0 pr-2 btn btn-secondary" aria-label="Toggle options menu"><i aria-hidden="true" class="fa fa-caret-down fa-fw"></i></button>
</div>
</div>
</div>
</FormLabelGroup >
);
}

it('uses the clear button', () => {
let cleared = false;

cy.mount(
<FutureTestbed
onClear={() => {
cleared = true;
}}
/>
);

cy.component(comp.Combobox, 'some label').clear();
eventually(() => cleared === true);
})

it('tolerates disabled clear button', () => {
let cleared = false;

cy.mount(
<FutureTestbed
clearable={false}
onClear={() => {
cleared = true;
}}
/>
);

cy.component(comp.Combobox, 'some label').clear();
cy.wait(1000);
expect(cleared).to.equal(false);
})
})
});

context('Select component', () => {
Expand Down
20 changes: 20 additions & 0 deletions cypress/component/commands/fill.cy.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,26 @@ describe('cy.fill', () => {
);
cy.component(comp.Combobox, 'some label').fill('alpha');
eventually(() => selected === 'alpha');
cy.component(comp.Combobox, 'some label').fill('charlie');
eventually(() => selected === 'charlie');
});

it('cooperates with clear', () => {
let selected;

cy.mount(
<Testbed
onChange={(v) => {
selected = v;
}}
/>
);
cy.component(comp.Combobox, 'some label').fill('alpha');
eventually(() => selected === 'alpha');
cy.component(comp.Combobox, 'some label').clear();
eventually(() => selected === undefined);
cy.component(comp.Combobox, 'some label').fill('charlie');
eventually(() => selected === 'charlie');
});

// TODO: figure out how to intercept Cypress command errors
Expand Down
20 changes: 14 additions & 6 deletions src/commands/actions/clear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,20 @@ export function clear(
});

if (isGearsCombobox) {
return cy
.wrap(prevSubject, QUIET)
.find('[data-testid=combobox-input]', QUIET)
.focus(QUIET)
.type('{backspace}{backspace}', QUIET)
.then(blurIfNecessary);
const btn = prevSubject.find('[data-testid=combobox-clear]');
if (btn.length === 1 && !btn.prop('disabled')) {
// testing hook is present; use it for maximum stability
return cy
.wrap(btn, QUIET).click().wrap(prevSubject, QUIET).then(blurIfNecessary);
} else {
// fall back to UI gesture that should work in most cases
return cy
.wrap(prevSubject, QUIET)
.find('[data-testid=combobox-input]', QUIET)
.focus(QUIET)
.type('{backspace}{backspace}', QUIET)
.then(blurIfNecessary);
}
}

if (isGearsSelect) {
Expand Down
9 changes: 2 additions & 7 deletions src/commands/actions/fill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ export function fill(
'react-gears-cypress: cy.fill with multiple values is not yet supported; sorry!'
);

cy.wrap(prevSubject, QUIET).clear(QUIET);
cy.wrap(prevSubject, QUIET)
.find('[data-testid=combobox-input]', QUIET)
.focus()
.type('{backspace}{backspace}', QUIET)
.type(value, FORCE_QUIET);
.type(value, FORCE_QUICK_QUIET);
return cy
.contains('button.dropdown-item.active', value, QUIET)
.click(QUIET);
Expand All @@ -71,13 +70,9 @@ export function fill(
'react-gears-cypress: cy.fill with multiple values is not yet supported; sorry!'
);

// NB repeatedly re-finding elements relative to subject in order to
// deal with DOM churn
// TODO: is this useful anymore under Cypress 12?
cy.wrap(prevSubject, QUIET).clear(QUIET);
cy.wrap(prevSubject, QUIET)
.find('input', QUIET)
.focus(QUIET)
.type(value, FORCE_QUICK_QUIET);
cy.wrap(prevSubject, QUIET)
.parent(QUIET)
Expand Down

0 comments on commit 106b458

Please sign in to comment.