// Component tests for usa-tag
import './index.ts';
describe('USA Tag Component Tests', () => {
it('should render tag with default properties', () => {
cy.mount(` `);
cy.get('usa-tag').should('exist');
cy.get('.usa-tag').should('exist');
cy.get('.usa-tag').should('contain.text', 'Default Tag');
});
it('should render tag with slot content', () => {
cy.mount(`Slotted Content `);
cy.get('.usa-tag').should('contain.text', 'Slotted Content');
});
it('should prefer text property over slot content', () => {
cy.mount(`Slot Content `);
cy.get('.usa-tag').should('contain.text', 'Text Property');
cy.get('.usa-tag').should('not.contain.text', 'Slot Content');
});
it('should render big tag variant', () => {
cy.mount(` `);
cy.get('.usa-tag').should('have.class', 'usa-tag--big');
});
it('should render normal size tag by default', () => {
cy.mount(` `);
cy.get('.usa-tag').should('not.have.class', 'usa-tag--big');
});
it('should render removable tag', () => {
cy.mount(` `);
cy.get('.usa-tag').should('have.class', 'usa-tag--removable');
cy.get('.usa-tag__remove').should('exist');
cy.get('.usa-tag__remove').should('have.attr', 'type', 'button');
cy.get('.usa-tag__remove').should('have.attr', 'aria-label', 'Remove tag: Removable Tag');
});
it('should not render remove button for non-removable tags', () => {
cy.mount(` `);
cy.get('.usa-tag').should('not.have.class', 'usa-tag--removable');
cy.get('.usa-tag__remove').should('not.exist');
});
it('should emit tag-remove event when remove button is clicked', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
const removeSpy = cy.stub();
tag.addEventListener('tag-remove', removeSpy);
cy.get('.usa-tag__remove').click();
cy.then(() => {
expect(removeSpy).to.have.been.calledWith(
Cypress.sinon.match({
detail: Cypress.sinon.match({
text: 'Remove Me',
value: 'tag-123'
})
})
);
});
});
});
it('should remove tag from DOM when remove button is clicked', () => {
cy.mount(`
`);
cy.get('usa-tag').should('exist');
cy.get('.usa-tag__remove').click();
cy.get('usa-tag').should('not.exist');
});
it('should handle remove button with keyboard interaction', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
const removeSpy = cy.stub();
tag.addEventListener('tag-remove', removeSpy);
cy.get('.usa-tag__remove').focus().type('{enter}');
cy.then(() => {
expect(removeSpy).to.have.been.called;
});
});
});
it('should stop event propagation on remove', () => {
cy.mount(`
`);
cy.window().then((win) => {
// Container click should not be called due to stopPropagation
expect(containerClickSpy).not.to.have.been.called;
});
});
});
it('should render remove button with proper SVG icon', () => {
cy.mount(` `);
cy.get('.usa-tag__remove .usa-icon').should('exist');
cy.get('.usa-tag__remove .usa-icon')
.should('have.attr', 'aria-hidden', 'true')
.should('have.attr', 'focusable', 'false')
.should('have.attr', 'role', 'img')
.should('have.attr', 'viewBox', '0 0 24 24')
.should('have.attr', 'width', '16')
.should('have.attr', 'height', '16');
cy.get('.usa-tag__remove .usa-icon path').should('exist');
});
it('should handle big removable tag', () => {
cy.mount(` `);
cy.get('.usa-tag')
.should('have.class', 'usa-tag--big')
.should('have.class', 'usa-tag--removable');
cy.get('.usa-tag__remove').should('exist');
});
it('should handle value property for identification', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
expect(tag.value).to.equal('unique-id-123');
});
});
it('should handle empty text gracefully', () => {
cy.mount(` `);
cy.get('.usa-tag').should('exist');
cy.get('.usa-tag').should('be.empty');
});
it('should handle complex slotted content', () => {
cy.mount(`
Important Tag
`);
cy.get('.usa-tag .custom-content').should('exist');
cy.get('.usa-tag strong').should('contain.text', 'Important');
});
it('should handle dynamic property updates', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
// Initially not big
cy.get('.usa-tag').should('not.have.class', 'usa-tag--big');
// Change to big
tag.big = true;
cy.get('.usa-tag').should('have.class', 'usa-tag--big');
// Initially not removable
cy.get('.usa-tag__remove').should('not.exist');
// Change to removable
tag.removable = true;
cy.get('.usa-tag').should('have.class', 'usa-tag--removable');
cy.get('.usa-tag__remove').should('exist');
// Update text
tag.text = 'Updated Text';
cy.get('.usa-tag').should('contain.text', 'Updated Text');
});
});
it('should handle focus states on remove button', () => {
cy.mount(` `);
cy.get('.usa-tag__remove').focus();
cy.focused().should('have.class', 'usa-tag__remove');
cy.focused().should('be.visible');
});
it('should handle multiple tags in a group', () => {
cy.mount(`
`);
cy.get('usa-tag').should('have.length', 4);
cy.get('.usa-tag--big').should('have.length', 2);
cy.get('.usa-tag--removable').should('have.length', 2);
cy.get('.usa-tag__remove').should('have.length', 2);
});
it('should handle removal of multiple tags', () => {
cy.mount(`
`);
cy.get('usa-tag').should('have.length', 3);
// Remove first tag
cy.get('#tag1 .usa-tag__remove').click();
cy.get('usa-tag').should('have.length', 2);
cy.get('#tag1').should('not.exist');
// Remove second tag
cy.get('#tag2 .usa-tag__remove').click();
cy.get('usa-tag').should('have.length', 1);
cy.get('#tag2').should('not.exist');
// Third tag should still exist
cy.get('#tag3').should('exist');
});
it('should handle tag removal events in sequence', () => {
cy.mount(`
`);
cy.window().then((win) => {
});
cy.get('#tag1 .usa-tag__remove').click();
cy.get('#tag2 .usa-tag__remove').click();
cy.then(() => {
expect(removeEvents).to.have.length(2);
expect(removeEvents[0]).to.deep.equal({ text: 'Tag A', value: 'a' });
expect(removeEvents[1]).to.deep.equal({ text: 'Tag B', value: 'b' });
});
});
});
it('should handle accessibility correctly', () => {
cy.mount(`
`);
cy.get('.usa-tag__remove')
.should('have.attr', 'type', 'button')
.should('have.attr', 'aria-label', 'Remove tag: Accessible Removable Tag');
cy.get('.usa-tag__remove .usa-icon')
.should('have.attr', 'aria-hidden', 'true')
.should('have.attr', 'focusable', 'false')
.should('have.attr', 'role', 'img');
});
it('should handle keyboard navigation', () => {
cy.mount(`
Next Element
`);
// Tab through remove buttons
cy.get('#tag1 .usa-tag__remove').focus();
cy.focused().should('contain.text', '');
cy.focused().should('have.attr', 'aria-label').and('include', 'First Tag');
cy.focused().tab();
cy.focused().should('have.attr', 'aria-label').and('include', 'Second Tag');
cy.focused().tab();
cy.focused().should('have.id', 'next-element');
});
it('should handle edge cases for remove functionality', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
// Add multiple event listeners to test event handling
const removeSpy1 = cy.stub();
const removeSpy2 = cy.stub();
tag.addEventListener('tag-remove', removeSpy1);
tag.addEventListener('tag-remove', removeSpy2);
cy.get('.usa-tag__remove').click();
cy.then(() => {
expect(removeSpy1).to.have.been.called;
expect(removeSpy2).to.have.been.called;
});
});
});
it('should handle rapid click events', () => {
cy.mount(` `);
cy.window().then((win) => {
const tag = win.document.getElementById('test-tag') as any;
const removeSpy = cy.stub();
tag.addEventListener('tag-remove', removeSpy);
// Multiple rapid clicks should only trigger once (since tag gets removed)
cy.get('.usa-tag__remove').click().click().click();
cy.then(() => {
expect(removeSpy).to.have.been.calledOnce;
});
// Tag should be removed
cy.get('#test-tag').should('not.exist');
});
});
it('should handle custom CSS classes', () => {
cy.mount(`
`);
cy.get('usa-tag')
.should('have.class', 'custom-tag-class')
.should('have.class', 'special-styling');
cy.get('.usa-tag')
.should('exist')
.should('have.class', 'usa-tag--big');
});
it('should handle tag collections with mixed properties', () => {
cy.mount(`
Slotted Content
`);
cy.get('usa-tag').should('have.length', 5);
// Check regular tag
cy.get('usa-tag[value="regular"] .usa-tag')
.should('not.have.class', 'usa-tag--big')
.should('not.have.class', 'usa-tag--removable');
// Check big tag
cy.get('usa-tag[value="big"] .usa-tag')
.should('have.class', 'usa-tag--big')
.should('not.have.class', 'usa-tag--removable');
// Check removable tag
cy.get('usa-tag[value="removable"] .usa-tag')
.should('not.have.class', 'usa-tag--big')
.should('have.class', 'usa-tag--removable');
// Check big removable tag
cy.get('usa-tag[value="big-removable"] .usa-tag')
.should('have.class', 'usa-tag--big')
.should('have.class', 'usa-tag--removable');
// Check slotted content
cy.get('usa-tag[value="slotted-tag"] .usa-tag em')
.should('contain.text', 'Slotted Content');
});
it('should be accessible', () => {
cy.mount(`
Selected Tags
Click the × button to remove unwanted tags:
`);
cy.injectAxe();
cy.checkAccessibility();
});
});