diff --git a/package.json b/package.json index c686236202..50f879245e 100644 --- a/package.json +++ b/package.json @@ -122,8 +122,8 @@ }, "dependencies": { "@date-fns/tz": "1.4.1", - "@digdir/designsystemet-css": "1.11.1", - "@digdir/designsystemet-react": "1.11.1", + "@digdir/designsystemet-css": "1.18.0", + "@digdir/designsystemet-react": "1.18.0", "@navikt/aksel-icons": "8.10.5", "@tanstack/react-query": "5.100.10", "@terraformer/wkt": "2.2.1", diff --git a/src/components/atoms/AltinnAttachments.tsx b/src/components/atoms/AltinnAttachments.tsx index 9ecafebf2d..cd28d1785c 100644 --- a/src/components/atoms/AltinnAttachments.tsx +++ b/src/components/atoms/AltinnAttachments.tsx @@ -5,7 +5,6 @@ import { Link, List } from '@digdir/designsystemet-react'; import cn from 'classnames'; import classes from 'src/components/atoms/AltinnAttachment.module.css'; -import { MainAttachmentHeader } from 'src/components/atoms/AttachmentHeader'; import { Lang } from 'src/features/language/Lang'; import { useCurrentLanguage } from 'src/features/language/LanguageProvider'; import { useLanguage } from 'src/features/language/useLanguage'; @@ -39,7 +38,7 @@ export function AltinnAttachments({ id={id} data-testid='attachment-list' > - + {title} { expect(console.error).not.toHaveBeenCalled(); - const showDetailsButton = screen.getByRole('button', { name: 'Vis detaljer om feilen' }); - await user.click(showDetailsButton); + const detailsGroup = screen.getByRole('group'); + expect(detailsGroup).toHaveTextContent('Vis detaljer om feilen'); + const summary = detailsGroup.querySelector('summary'); + if (!summary) { + throw new Error('Expected a inside the details group'); + } + await user.click(summary); expect(screen.getByText('Error test message')).toBeInTheDocument(); const writeTextMock = jest.spyOn(navigator.clipboard, 'writeText').mockResolvedValue(); diff --git a/src/layout/Accordion/Accordion.test.tsx b/src/layout/Accordion/Accordion.test.tsx index 49aac58edd..6df8a15d34 100644 --- a/src/layout/Accordion/Accordion.test.tsx +++ b/src/layout/Accordion/Accordion.test.tsx @@ -9,23 +9,23 @@ describe('Accordion', () => { it('should display text from textResourceBindings', async () => { await render({ title: 'Accordion title' }); - expect(await screen.findByRole('button', { name: /accordion title/i })).toBeInTheDocument(); + expect(await screen.findByRole('group')).toHaveTextContent(/accordion title/i); }); it('should display text from textResourceBindings if an ID to a text resource is used as title', async () => { await render({ title: 'accordion.title' }); - expect(await screen.findByRole('button', { name: /this is a title/i })).toBeInTheDocument(); + expect(await screen.findByRole('group')).toHaveTextContent(/this is a title/i); }); it('should open accordion by default if openByDefault is set to true', async () => { await render({ openByDefault: true, title: 'accordion.title' }); - expect(await screen.findByRole('button', { name: /this is a title/i })).toHaveAttribute('aria-expanded', 'true'); + expect(await screen.findByRole('group')).toHaveAttribute('open'); }); it('accordion should be closed by default if openByDefault is set to false', async () => { await render({ openByDefault: false, title: 'accordion.title' }); - expect(await screen.findByRole('button', { name: /this is a title/i })).toHaveAttribute('aria-expanded', 'false'); + expect(await screen.findByRole('group')).not.toHaveAttribute('open'); }); }); diff --git a/src/layout/AttachmentList/AttachmentListComponent.tsx b/src/layout/AttachmentList/AttachmentListComponent.tsx index 9c290c649e..6b8a170048 100644 --- a/src/layout/AttachmentList/AttachmentListComponent.tsx +++ b/src/layout/AttachmentList/AttachmentListComponent.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { AltinnAttachments } from 'src/components/atoms/AltinnAttachments'; +import { MainAttachmentHeader } from 'src/components/atoms/AttachmentHeader'; import { AttachmentGroupings } from 'src/components/organisms/AttachmentGroupings'; import { useApplicationMetadata } from 'src/features/applicationMetadata/ApplicationMetadataProvider'; import { useInstanceDataElements } from 'src/features/instance/InstanceContext'; @@ -82,7 +83,7 @@ export function AttachmentListComponent({ baseComponentId }: PropsFromGenericCom ) : ( : undefined} showLinks={showLinks} showDescription={showDescription} /> diff --git a/src/layout/Dropdown/DropdownComponent.test.tsx b/src/layout/Dropdown/DropdownComponent.test.tsx index 16641f53fe..0d2cf14b51 100644 --- a/src/layout/Dropdown/DropdownComponent.test.tsx +++ b/src/layout/Dropdown/DropdownComponent.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { jest } from '@jest/globals'; -import { act, screen, waitFor } from '@testing-library/react'; +import { act, fireEvent, screen, waitFor } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; import type { AxiosResponse } from 'axios'; @@ -104,6 +104,43 @@ describe('DropdownComponent', () => { ); }); + it('should commit the new value after confirming alertOnChange', async () => { + const { formDataMethods } = await render({ + component: { + alertOnChange: true, + }, + options: countries, + queries: { + fetchFormData: async () => ({ + ...getFormDataMockForRepGroup(), + myDropdown: 'norway', + }), + }, + }); + + expect(await screen.findByRole('combobox')).toHaveValue('Norway'); + + await userEvent.click(screen.getByRole('combobox')); + await userEvent.click(screen.getByRole('option', { name: /sweden/i })); + + // Mimic the alert popover stealing focus, which blurs the combobox and reverts the input display + // back to the previously-committed value before the change is confirmed. + fireEvent.blur(screen.getByRole('combobox')); + + // Alert should appear; confirm the change + const confirmButton = await screen.findByRole('button', { name: /bekreft|confirm/i }); + await userEvent.click(confirmButton); + + await waitFor(() => + expect(formDataMethods.setLeafValue).toHaveBeenCalledWith({ + reference: { field: 'myDropdown', dataType: defaultDataTypeMock }, + newValue: 'sweden', + }), + ); + + expect(screen.getByRole('combobox')).toHaveValue('Sweden'); + }); + it('should show as readonly when readOnly is true', async () => { await render({ component: { diff --git a/src/layout/Dropdown/DropdownComponent.tsx b/src/layout/Dropdown/DropdownComponent.tsx index ed80f7f1c9..9aca3d0cf5 100644 --- a/src/layout/Dropdown/DropdownComponent.tsx +++ b/src/layout/Dropdown/DropdownComponent.tsx @@ -104,6 +104,10 @@ export function DropdownComponent({ baseComponentId, overrideDisplay }: PropsFro )} optionFilter(args, selectedLabels)} data-size='sm' diff --git a/src/setupTests.ts b/src/setupTests.ts index 16ce7e38e8..f251638131 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -60,6 +60,11 @@ Element.prototype.getClientRects = () => ({ [Symbol.iterator]: jest.fn(), }); +// jsdom doesn't implement elementFromPoint, which Designsystemet's Popover uses +// in its `isTopLayer` check when handling Escape keydown. Returning the open +// popover element makes the check pass so ESC actually closes the popover in tests. +document.elementFromPoint = () => document.querySelector('[popover]'); + // Forcing a low timeout for useDelayedSaveState() global.delayedSaveState = 50; diff --git a/test/e2e/integration/frontend-test/components.ts b/test/e2e/integration/frontend-test/components.ts index e2aec466ce..8140e2d8ad 100644 --- a/test/e2e/integration/frontend-test/components.ts +++ b/test/e2e/integration/frontend-test/components.ts @@ -479,22 +479,17 @@ describe('UI Components', () => { cy.gotoHiddenPage('label-data-bindings'); cy.get('#form-content-colorsCheckboxes').click(); + // After selecting an option, the DS combobox renders a removable chip (a ) whose + // accessible name is "