From fb37469854b9c8d7fc3bbd80eace1eeb93a0eb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aliz=C3=A9=20Debray?= Date: Wed, 3 Jul 2024 14:45:00 +0200 Subject: [PATCH] fix e2e --- .../components/cypress/e2e/collapsible.cy.ts | 72 ++++++++++++------- .../components/cypress/support/commands.ts | 10 ++- .../components/cypress/support/index.d.ts | 1 + .../post-collapsible-trigger.tsx | 13 ++-- .../post-collapsible/post-collapsible.scss | 3 - .../post-collapsible/post-collapsible.tsx | 16 +---- .../collapsible.snapshot.stories.ts | 8 ++- 7 files changed, 72 insertions(+), 51 deletions(-) diff --git a/packages/components/cypress/e2e/collapsible.cy.ts b/packages/components/cypress/e2e/collapsible.cy.ts index f7d2d8a5b7..5144890858 100644 --- a/packages/components/cypress/e2e/collapsible.cy.ts +++ b/packages/components/cypress/e2e/collapsible.cy.ts @@ -3,57 +3,75 @@ const COLLAPSIBLE_ID = '6a91848c-16ec-4a23-bc45-51c797b5b2c3'; describe('collapsible', () => { describe('default', () => { beforeEach(() => { - cy.getComponent('collapsible', COLLAPSIBLE_ID); - cy.get('@collapsible').find('.collapse').as('collapse'); - cy.get(`#button--${COLLAPSIBLE_ID}--default`).as('toggler'); + cy.getComponents(COLLAPSIBLE_ID, 'default', 'post-collapsible', 'post-collapsible-trigger'); + cy.get('@collapsible-trigger').find('.btn').as('trigger'); }); - it('should render', () => { + it('should have a collapsible', () => { cy.get('@collapsible').should('exist'); }); - it('should have a collapse', () => { - cy.get('@collapse').should('exist'); + it('should have a trigger', () => { + cy.get('@trigger').should('exist'); }); - it('should have a toggle button', () => { - cy.get('@toggler').should('exist'); + it('should show the collapsible', () => { + cy.get('@collapsible').should(`be.visible`); }); - it('should be expanded', () => { - cy.get('@collapse').should(`be.visible`); + it('should set the correct ARIA attribute on the trigger', () => { + cy.get('@collapsible') + .invoke('attr', 'id') + .then(collapsibleId => { + cy.get('@trigger').should('have.attr', 'aria-controls', collapsibleId); + }); + cy.get('@trigger').should('have.attr', 'aria-expanded', 'true'); }); - it('should be collapsed after clicking on the toggle button once', () => { - cy.get('@toggler').click(); - cy.get('@collapse').should(`be.hidden`); + it('should hide the collapsible after clicking on the trigger once', () => { + cy.get('@trigger').click(); + cy.get('@collapsible').should(`be.hidden`); }); - it('should be expanded after clicking on the toggle button twice', () => { - cy.get('@toggler').dblclick(); - cy.get('@collapse').should(`be.visible`); + it('should update the "aria-expanded" attribute after hiding the collapsible', () => { + cy.get('@trigger').click(); + cy.get('@trigger').should('have.attr', 'aria-expanded', 'false'); + }); + + it('should show the collapsible after clicking on the trigger twice', () => { + cy.get('@trigger').dblclick(); + cy.get('@collapsible').should(`be.visible`); + }); + + it('should update the "aria-expanded" attribute after showing the collapsible', () => { + cy.get('@trigger').click(); + cy.get('@trigger').should('have.attr', 'aria-expanded', 'true'); }); }); describe('initially collapsed', () => { beforeEach(() => { - cy.getComponent('collapsible', COLLAPSIBLE_ID, 'initially-collapsed'); - cy.get('@collapsible').find('.collapse').as('collapse'); - cy.get(`#button--${COLLAPSIBLE_ID}--initially-collapsed`).as('toggler'); + cy.getComponents( + COLLAPSIBLE_ID, + 'initially-collapsed', + 'post-collapsible', + 'post-collapsible-trigger', + ); + cy.get('@collapsible-trigger').find('.btn').as('trigger'); }); - it('should be collapsed', () => { - cy.get('@collapse').should(`be.hidden`); + it('should hide the collapsible', () => { + cy.get('@collapsible').should(`be.hidden`); }); - it('should be expanded after clicking on the toggle button once', () => { - cy.get('@toggler').click(); - cy.get('@collapse').should(`be.visible`); + it('should show the collapsible after clicking on the trigger once', () => { + cy.get('@trigger').click(); + cy.get('@collapsible').should(`be.visible`); }); - it('should be collapsed after clicking on the toggle button twice', () => { - cy.get('@toggler').dblclick(); - cy.get('@collapse').should(`be.hidden`); + it('should hide the collapsible after clicking on the trigger twice', () => { + cy.get('@trigger').dblclick(); + cy.get('@collapsible').should(`be.hidden`); }); }); }); diff --git a/packages/components/cypress/support/commands.ts b/packages/components/cypress/support/commands.ts index 29e8f58b8c..20f89a741e 100644 --- a/packages/components/cypress/support/commands.ts +++ b/packages/components/cypress/support/commands.ts @@ -49,10 +49,16 @@ export const isInViewport = function (_chai: Chai.ChaiStatic) { chai.use(isInViewport); Cypress.Commands.add('getComponent', (component: string, id: string, story = 'default') => { + cy.getComponents(id, story, component); +}); + +Cypress.Commands.add('getComponents', (id: string, story: string, ...components: string[]) => { cy.visit(`/iframe.html?id=${id}--${story}`); - const alias = component.replace(/^post-/, ''); - cy.get(`post-${alias}`, { timeout: 30000 }).as(alias); + components.forEach(component => { + const alias = component.replace(/^post-/, ''); + cy.get(`post-${alias}.hydrated`, { timeout: 30000 }).as(alias); + }); cy.injectAxe(); }); diff --git a/packages/components/cypress/support/index.d.ts b/packages/components/cypress/support/index.d.ts index d7b6a2cd32..96fbc79c05 100644 --- a/packages/components/cypress/support/index.d.ts +++ b/packages/components/cypress/support/index.d.ts @@ -2,6 +2,7 @@ declare global { namespace Cypress { interface Chainable { getComponent(component: string, id: string, story?: string): Chainable; + getComponents(id: string, story: string, ...component: string[]): Chainable; getSnapshots(component: string): Chainable; checkAriaExpanded( controlledElementSelector: string, diff --git a/packages/components/src/components/post-collapsible-trigger/post-collapsible-trigger.tsx b/packages/components/src/components/post-collapsible-trigger/post-collapsible-trigger.tsx index b5e6b3bc98..961181183c 100644 --- a/packages/components/src/components/post-collapsible-trigger/post-collapsible-trigger.tsx +++ b/packages/components/src/components/post-collapsible-trigger/post-collapsible-trigger.tsx @@ -17,15 +17,20 @@ export class PostCollapsibleTrigger { @Prop() for: string; @Watch('for') - setAriaControls() { + setAriaAttributes() { checkNonEmpty(this.for, 'The post-collapsible-trigger "for" prop is required.'); checkType(this.for, 'string', 'The post-collapsible-trigger "for" prop should be a id.'); // Add collapsible id to aria-controls - if (this.trigger) this.trigger.setAttribute('aria-controls', this.for); + if (this.trigger) { + this.trigger.setAttribute('aria-controls', this.for); + + const isOpen = !this.collapsible?.collapsed; + if (isOpen !== undefined) this.trigger.setAttribute('aria-expanded', `${isOpen}`); + } } - componentDidLoad() { + connectedCallback() { const firstChild = this.host.children[0]; if (firstChild && firstChild.nodeType === Node.ELEMENT_NODE) { this.trigger = firstChild as HTMLElement; @@ -43,7 +48,7 @@ export class PostCollapsibleTrigger { this.trigger.setAttribute('role', 'button'); } - this.setAriaControls(); + this.setAriaAttributes(); } @Listen('pointerdown') diff --git a/packages/components/src/components/post-collapsible/post-collapsible.scss b/packages/components/src/components/post-collapsible/post-collapsible.scss index 0aaf688255..20947d5cd1 100644 --- a/packages/components/src/components/post-collapsible/post-collapsible.scss +++ b/packages/components/src/components/post-collapsible/post-collapsible.scss @@ -1,7 +1,4 @@ :host { display: block; -} - -.collapse { overflow: hidden; } diff --git a/packages/components/src/components/post-collapsible/post-collapsible.tsx b/packages/components/src/components/post-collapsible/post-collapsible.tsx index 41a29b4323..56ca965b7f 100644 --- a/packages/components/src/components/post-collapsible/post-collapsible.tsx +++ b/packages/components/src/components/post-collapsible/post-collapsible.tsx @@ -7,7 +7,6 @@ import { Host, Method, Prop, - State, Watch, } from '@stencil/core'; import { version } from '@root/package.json'; @@ -26,12 +25,9 @@ import { checkEmptyOrType, isMotionReduced } from '@/utils'; export class PostCollapsible { private isLoaded = false; private isOpen = true; - private collapsible: HTMLElement; @Element() host: HTMLPostCollapsibleElement; - @State() id: string; - /** * If `true`, the element is initially collapsed otherwise it is displayed. */ @@ -57,10 +53,6 @@ export class PostCollapsible { this.validateCollapsed(); } - componentWillRender() { - this.id = this.host.id || `c${crypto.randomUUID()}`; - } - componentDidLoad() { if (this.collapsed) void this.toggle(false); this.isLoaded = true; @@ -78,7 +70,7 @@ export class PostCollapsible { this.isOpen = !this.isOpen; if (this.isLoaded) this.postToggle.emit(this.isOpen); - const animation = open ? expand(this.collapsible) : collapse(this.collapsible); + const animation = open ? expand(this.host) : collapse(this.host); if (!this.isLoaded || isMotionReduced()) animation.finish(); @@ -91,10 +83,8 @@ export class PostCollapsible { render() { return ( - -
(this.collapsible = el)}> - -
+ + ); } diff --git a/packages/documentation/src/stories/components/collapsible/collapsible.snapshot.stories.ts b/packages/documentation/src/stories/components/collapsible/collapsible.snapshot.stories.ts index 38e0585172..4f9aa006cf 100644 --- a/packages/documentation/src/stories/components/collapsible/collapsible.snapshot.stories.ts +++ b/packages/documentation/src/stories/components/collapsible/collapsible.snapshot.stories.ts @@ -8,7 +8,6 @@ const { id, ...metaWithoutId } = meta; export default { ...metaWithoutId, - decorators: [], title: 'Snapshots', }; @@ -16,13 +15,18 @@ type Story = StoryObj; export const Collapsible: Story = { render: (_args: Args, context: StoryContext) => { + let index = 0; + const templateVariants = bombArgs({ collapsed: [false, true], }).map((args: Args) => { return html`

collapsed: ${args.collapsed}

- ${meta.render?.({ ...context.args, ...Default.args, ...args }, context)} + ${meta.render?.( + { ...context.args, ...Default.args, ...args }, + { ...context, id: `${context.id}-${index++}` }, + )}
`; });