cypress/e2e/forms/selects.cy.ts
describe('Selects', () => {
before(() => {
cy.visit('/selects');
cy.injectAxe();
cy.get('.page-loader').should('not.exist', { timeout: 20000 });
});
const shouldBeNotFocused = () =>
cy.get('.ngx-select-input-underline .underline-fill').should('have.css', 'width', '0px');
const shouldBeFocused = () =>
cy.get('.ngx-select-input-underline .underline-fill').should('not.have.css', 'width', '0px');
const shouldBeNotActive = () => cy.root().should('not.have.class', 'active');
const shouldBeActive = () => cy.root().should('have.class', 'active');
it('have no detectable a11y violations on load', () => {
cy.get('ngx-select:not(.autosize) ngx-select-input').withinEach($el => {
cy.checkA11y($el, {
rules: {
'color-contrast': { enabled: false }, // NOTE: to be evaluated by UIUX
label: { enabled: false } // TODO: fix these
}
} as any);
});
});
describe('Basic Input', () => {
beforeEach(() => {
cy.get('ngx-section').first().as('SUT');
cy.get('@SUT').find('ngx-select').first().as('CUT');
cy.get('@CUT').ngxClose();
cy.get('@CUT').clear();
});
it('has a label', () => {
cy.get('@CUT').ngxFindLabel().should('contain.text', 'Attack Type');
});
it('selects and clears value', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'DDOS';
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
it('selects and clears value by number', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
cy.get('@CUT').select(2).ngxGetValue().should('equal', 'Physical');
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
it('deselects on click', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'DDOS';
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').ngxOpen();
cy.get('@CUT').find('.ngx-select-dropdown-option').contains(text).click();
cy.get('@CUT').ngxGetValue().should('equal', '');
});
it('selects and clears value twice', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'DDOS';
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
it('is keyboard accessible', () => {
cy.get('@SUT').find('h4').contains('Basic').click();
cy.get('@CUT').within(() => {
// Starts out not focused not open
shouldBeNotFocused();
shouldBeNotActive();
// Tab into the select, now focused but still closed
cy.realPress('Tab');
shouldBeFocused();
shouldBeNotActive();
// Down arrow to open and select first item
cy.realPress('ArrowDown');
shouldBeFocused();
shouldBeActive();
cy.get('.ngx-select-dropdown-options li li').within(() => {
cy.root().first().should('have.class', 'active'); // active
cy.root().last().should('not.have.class', 'active'); // not active
cy.realPress('ArrowDown').realPress('ArrowDown');
cy.root().first().should('not.have.class', 'active'); // not active
cy.root().last().should('have.class', 'active'); // active
});
// Escape to close list
cy.realPress('Escape');
shouldBeFocused();
shouldBeNotActive();
// Arrow up to open and select last item
cy.realPress('ArrowUp');
shouldBeFocused();
shouldBeActive();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(10); // Needed for testing!!!
cy.get('.ngx-select-dropdown-options li li').within(() => {
cy.root().first().should('not.have.class', 'active'); // not active
cy.root().last().should('have.class', 'active'); // active
cy.realPress('ArrowUp');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(10); // Needed for testing!!!
cy.realPress('ArrowUp');
cy.root().first().should('have.class', 'active'); // active
cy.root().last().should('not.have.class', 'active'); // not active
});
// Enter selects an option and closes the list
cy.realPress('Enter');
shouldBeFocused();
shouldBeNotActive();
cy.root().ngxGetValue().should('equal', 'Breach');
// Space opens
cy.realPress('Space');
shouldBeFocused();
shouldBeActive();
// Space selects an option but leaves list open
cy.realPress('ArrowDown');
cy.realPress('Space');
cy.root().ngxGetValue().should('equal', 'DDOS');
shouldBeFocused();
shouldBeActive();
// Can deselect
cy.realPress('Space');
cy.root().ngxGetValue().should('equal', '');
shouldBeFocused();
shouldBeActive();
// Tab away
cy.root().ngxClose();
cy.realPress('Tab');
shouldBeNotFocused();
shouldBeNotActive();
});
});
});
describe('Tagging', () => {
beforeEach(() => {
cy.get('ngx-section[data-cy=tagging]').as('SUT');
cy.get('@SUT').find('ngx-select').first().as('CUT');
cy.get('@CUT').ngxClose();
});
it('has a label', () => {
cy.get('@CUT').ngxFindLabel().should('contain.text', 'Tagging');
});
it('selects and clears existing values', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'DDOS';
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
// TODO(ngx-ui-testing): tagging should return an array of values
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
it('can add and clear a new value', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'Other';
// TODO(ngx-ui-testing): support ngxFill for tagging
cy.get('@CUT').find('input').click().type(text).type('{enter}');
cy.get('@CUT').ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
it('can add and clear multiple values', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
cy.get('@CUT').select('DDOS').ngxGetValue().should('equal', 'DDOS');
cy.get('@CUT').find('input').click().type('Other').type('{enter}');
cy.get('@CUT').ngxGetValue().should('contain', 'DDOS').should('contain', 'Other');
cy.get('@CUT').find('.ngx-select-clear').first().click();
cy.get('@CUT').find('.ngx-select-clear').first().click();
});
it('is keyboard accessible', () => {
cy.get('@SUT').find('h4').contains('Basic').click();
cy.get('@CUT').within(() => {
// Starts out not focused not open
shouldBeNotFocused();
shouldBeNotActive();
// Tab into the select, now focused and open
cy.realPress('Tab');
shouldBeFocused();
shouldBeActive();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(100); // Wait for element to refocus
cy.focused().type('Other{enter}'); // Input should be focused
cy.root().ngxGetValue().should('contain', 'Other');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(100); // Wait for element to refocus
// Down arrow to select second item, closes list, stays active
cy.realPress('ArrowDown');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(100); // Needed for testing!!!
cy.realPress('Enter');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(120); // Wait for element to refocus on input
shouldBeFocused();
shouldBeActive();
cy.root().ngxGetValue().should('contain', 'Other').should('contain', 'DDOS');
// Clears with backspace
cy.focused().type('{backspace}{backspace}{backspace}'); // For some reason needs three backspaces in testing
});
});
});
describe('Input with AbstractControl', () => {
beforeEach(() => {
cy.getByName('formCtrl1').as('CUT');
cy.get('[data-cy=reactiveFormSelectToggleBtn]').as('reactiveFormSelectToggleBtn');
});
it('should be able to be disabled', () => {
cy.get('@CUT').should('not.have.class', 'disabled');
cy.get('@reactiveFormSelectToggleBtn').click();
cy.get('@CUT').should('have.class', 'disabled');
});
it('should be able to get re-enabled', () => {
cy.get('@reactiveFormSelectToggleBtn').click();
cy.get('@CUT').should('not.have.class', 'disabled');
});
});
describe('Input with AbstractControl disabled by default', () => {
beforeEach(() => {
cy.getByName('formCtrl2').as('CUT');
});
it('should be able to be disabled', () => {
cy.get('@CUT').should('have.class', 'disabled');
});
});
describe('Filtering Input', () => {
beforeEach(() => {
cy.getByName('filtering').as('CUT');
});
it('has a label', () => {
cy.get('@CUT').ngxFindLabel().should('contain.text', 'Attack Type');
});
it('selects and clears value', () => {
const text = 'DDOS';
cy.get('@CUT').ngxFill(text).select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
});
describe('Templates', () => {
beforeEach(() => {
cy.get('[data-cy=templates]').as('CUT');
});
it('selects and clears value', () => {
cy.get('@CUT').ngxGetValue().should('equal', '');
const text = 'breach';
cy.get('@CUT').select(text).ngxGetValue().should('equal', text);
cy.get('@CUT').clear().ngxGetValue().should('equal', '');
});
});
describe('Multiple Select', () => {
beforeEach(() => {
cy.get('section header h1').contains('Multi Select').closest('ngx-section').as('SUT');
cy.get('@SUT').find('ngx-select').first().as('CUT');
});
it('selects and clears value', () => {
cy.get('@CUT').ngxGetValue().should('deep.equal', []);
cy.get('@CUT').select('DDOS').ngxGetValue().should('deep.equal', ['DDOS']);
cy.get('@CUT').select(['DDOS', 'Physical']).ngxGetValue().should('deep.equal', ['DDOS', 'Physical']);
cy.get('@CUT').clear().ngxGetValue().should('deep.equal', []);
});
it('is keyboard accessible', () => {
cy.get('@SUT').find('h4').contains('Basic').click();
cy.get('@CUT').within(() => {
// Starts out not focused not open
shouldBeNotFocused();
shouldBeNotActive();
// Tab into the select, now focused but still closed
cy.realPress('Tab');
shouldBeFocused();
shouldBeNotActive();
// Down arrow to open and select first item
cy.realPress('ArrowDown');
shouldBeFocused();
shouldBeActive();
cy.get('.ngx-select-dropdown-options li li').within(() => {
cy.root().first().should('have.class', 'active'); // active
cy.root().last().should('not.have.class', 'active'); // not active
cy.realPress('ArrowDown').realPress('ArrowDown');
cy.root().first().should('not.have.class', 'active'); // not active
cy.root().last().should('have.class', 'active'); // active
});
// Escape to close list
cy.realPress('Escape');
shouldBeFocused();
shouldBeNotActive();
// Arrow up to open and select last item
cy.realPress('ArrowUp');
shouldBeFocused();
shouldBeActive();
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(10); // Needed for testing!!!
cy.get('.ngx-select-dropdown-options li li').within(() => {
cy.root().first().should('not.have.class', 'active'); // not active
cy.root().last().should('have.class', 'active'); // active
cy.realPress('ArrowUp');
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(10); // Needed for testing!!!
cy.realPress('ArrowUp');
cy.root().first().should('have.class', 'active'); // active
cy.root().last().should('not.have.class', 'active'); // not active
});
// Enter selects an option and leaves list open
cy.realPress('Enter');
shouldBeFocused();
shouldBeActive();
cy.root().ngxGetValue().should('deep.equal', ['Breach']);
// Space selects an option but leaves list open
cy.realPress('ArrowDown');
cy.realPress('Space');
cy.root().ngxGetValue().should('deep.equal', ['Breach', 'DDOS']);
shouldBeFocused();
shouldBeActive();
// Can deselect an option
cy.realPress('ArrowUp');
cy.realPress('Space');
cy.root().ngxGetValue().should('deep.equal', ['DDOS']);
shouldBeFocused();
shouldBeActive();
cy.root().ngxClose();
cy.realPress('Tab');
shouldBeNotFocused();
shouldBeNotActive();
});
});
});
describe('Native Select', () => {
beforeEach(() => {
cy.get('[sectiontitle="Native"] select').first().as('CUT');
});
it('selects value', () => {
cy.get('@CUT').ngxGetValue().should('equal', 'Red');
cy.get('@CUT').select('Green').ngxGetValue().should('equal', 'Green');
cy.get('@CUT').select(2).ngxGetValue().should('equal', 'Blue-Green');
});
});
describe('Native MultiSelect', () => {
beforeEach(() => {
cy.get('[sectiontitle="Native"] select').eq(1).as('CUT');
});
it('selects value', () => {
cy.get('@CUT').ngxGetValue().should('deep.equal', []);
cy.get('@CUT').select('Green').ngxGetValue().should('deep.equal', ['Green']);
cy.get('@CUT').select(['Green', 'Red']).ngxGetValue().should('deep.equal', ['Red', 'Green']);
});
});
describe('Async', () => {
beforeEach(() => {
cy.get('[sectiontitle="Async"] ngx-select').first().as('CUT').scrollIntoView();
cy.intercept(`https://jsonplaceholder.typicode.com/posts?q=*`, {
delay: 600,
body: [
{
userId: 1,
id: 4,
title: 'eum et est occaecati',
body: 'ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit'
},
{
userId: 1,
id: 6,
title: 'dolorem eum magni eos aperiam quia',
body: 'ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae'
},
{
userId: 1,
id: 8,
title: 'dolorem dolore est ipsam',
body: 'dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae'
}
]
}).as('api');
});
it('selects value', () => {
cy.get('@CUT').ngxGetValue().should('deep.equal', '');
cy.get('@CUT').ngxOpen();
cy.get('@CUT').find('input').ngxFill('dolorem');
cy.wait('@api');
cy.get('@CUT').find('li.ngx-select-dropdown-option').should('have.length', 2);
cy.get('@CUT').select('dolorem eum magni eos aperiam quia');
cy.get('@CUT').ngxGetValue().should('deep.equal', 'dolorem eum magni eos aperiam quia');
});
});
describe('Close on body click', () => {
beforeEach(() => {
cy.asAllDataCy();
});
it('should close on input click', () => {
cy.get('@attackType').within(() => {
cy.get('.ngx-select-dropdown-options').should('not.exist');
cy.get('.ngx-select-input-box').click();
cy.get('.ngx-select-dropdown-options').first().scrollIntoView();
cy.get('.ngx-select-dropdown-options').should('be.visible');
});
cy.get('@attackTypeRequired').within(() => {
cy.get('.ngx-select-dropdown-options').should('not.exist');
cy.get('.ngx-select-input-box').click();
cy.get('.ngx-select-dropdown-options').first().scrollIntoView();
cy.get('.ngx-select-dropdown-options').should('be.visible');
});
// the current opened select should be closed
cy.get('@attackType').find('.ngx-select-dropdown-options').should('not.exist');
});
it('should close on caret down click', () => {
cy.get('@attackType').within(() => {
cy.get('.ngx-select-dropdown-options').should('not.exist');
cy.get('.ngx-select-caret').click();
cy.get('.ngx-select-dropdown-options').first().scrollIntoView();
cy.get('.ngx-select-dropdown-options').should('be.visible');
});
cy.get('@attackTypeRequired').within(() => {
cy.get('.ngx-select-dropdown-options').should('not.exist');
cy.get('.ngx-select-caret').click();
cy.get('.ngx-select-dropdown-options').first().scrollIntoView();
cy.get('.ngx-select-dropdown-options').should('be.visible');
});
// the current opened select should be closed
cy.get('@attackType').find('.ngx-select-dropdown-options').should('not.exist');
});
});
});