From efa85802c21e63e41dbce3517826090c8486e6dd Mon Sep 17 00:00:00 2001 From: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:28:21 -0400 Subject: [PATCH] test: [M3-7863] - Use `happy-dom` instead of `jsdom` in unit tests (#11085) * use `happy-dom` * first batch of fixes * another batch of fixes * another batch of fixes * fix ui package color * fix database test flake with longer timeout * try something * try running on macOS * oops * try different config * clean up test config options * try more forks * try more forks * go back to working config * run on ubuntu * Added changeset: Use `happy-dom` instead of `jsdom` in unit tests * add changeset for ui * fix last flake * feedback --------- Co-authored-by: Banks Nussman --- .../pr-11085-tests-1728657019139.md | 5 + packages/manager/package.json | 2 +- .../src/components/Avatar/Avatar.test.tsx | 6 +- .../src/components/BetaChip/BetaChip.test.tsx | 2 +- .../DescriptionList/DescriptionList.test.tsx | 2 +- .../HighlightedMarkdown.test.tsx.snap | 78 +++---- .../src/components/Notice/Notice.test.tsx | 4 +- .../manager/src/components/Tabs/Tab.test.tsx | 2 +- .../TextTooltip/TextTooltip.test.tsx | 2 +- .../DatabaseCreate/DatabaseCreate.test.tsx | 4 +- .../DatabaseLanding/DatabaseLanding.test.tsx | 36 ++-- .../CreateCluster/HAControlPlane.test.tsx | 6 +- .../Linodes/CloneLanding/Disks.test.tsx | 8 +- .../Linodes/LinodeCreate/VPC/VPC.test.tsx | 27 +-- .../Linodes/LinodeCreate/index.test.tsx | 4 +- .../LinodeIPAddressRow.test.tsx | 53 ++--- .../LinodeSettings/VPCPanel.test.tsx | 10 +- .../NodeBalancerConfigPanel.test.tsx | 9 +- .../NodeBalancerConfigurations.test.tsx | 22 +- .../NodeBalancerActionMenu.test.tsx | 20 +- .../NodeBalancerTableRow.test.tsx | 12 +- .../CreateOAuthClientDrawer.test.tsx | 8 +- .../features/Volumes/VolumeCreate.test.tsx | 2 +- .../src/utilities/omittedProps.test.tsx | 2 +- packages/manager/vite.config.ts | 3 +- .../pr-11085-tests-1728657169966.md | 5 + .../src/components/BetaChip/BetaChip.test.tsx | 2 +- packages/ui/vitest.config.ts | 2 +- yarn.lock | 196 +++--------------- 29 files changed, 214 insertions(+), 320 deletions(-) create mode 100644 packages/manager/.changeset/pr-11085-tests-1728657019139.md create mode 100644 packages/ui/.changeset/pr-11085-tests-1728657169966.md diff --git a/packages/manager/.changeset/pr-11085-tests-1728657019139.md b/packages/manager/.changeset/pr-11085-tests-1728657019139.md new file mode 100644 index 00000000000..882e40644d2 --- /dev/null +++ b/packages/manager/.changeset/pr-11085-tests-1728657019139.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Tests +--- + +Use `happy-dom` instead of `jsdom` in unit tests ([#11085](https://github.com/linode/manager/pull/11085)) diff --git a/packages/manager/package.json b/packages/manager/package.json index bd7aa7e825d..468da7d863f 100644 --- a/packages/manager/package.json +++ b/packages/manager/package.json @@ -195,7 +195,7 @@ "eslint-plugin-xss": "^0.1.10", "factory.ts": "^0.5.1", "glob": "^10.3.1", - "jsdom": "^24.1.1", + "happy-dom": "^15.7.4", "junit2json": "^3.1.4", "lint-staged": "^15.2.9", "mocha-junit-reporter": "^2.2.1", diff --git a/packages/manager/src/components/Avatar/Avatar.test.tsx b/packages/manager/src/components/Avatar/Avatar.test.tsx index 65e4ab1baa0..e8f7ae51d3a 100644 --- a/packages/manager/src/components/Avatar/Avatar.test.tsx +++ b/packages/manager/src/components/Avatar/Avatar.test.tsx @@ -31,7 +31,7 @@ describe('Avatar', () => { const avatarStyles = getComputedStyle(avatar); expect(getByTestId('avatar-letter')).toHaveTextContent('M'); - expect(avatarStyles.backgroundColor).toBe('rgb(1, 116, 188)'); // theme.color.primary.dark (#0174bc) + expect(avatarStyles.backgroundColor).toBe('#0174bc'); // theme.color.primary.dark (#0174bc) }); it('should render a background color from props', () => { @@ -48,8 +48,8 @@ describe('Avatar', () => { const avatarTextStyles = getComputedStyle(avatarText); // Confirm background color contrasts with text color. - expect(avatarStyles.backgroundColor).toBe('rgb(0, 0, 0)'); // black - expect(avatarTextStyles.color).toBe('rgb(255, 255, 255)'); // white + expect(avatarStyles.backgroundColor).toBe('#000000'); // black + expect(avatarTextStyles.color).toBe('#fff'); // white }); it('should render the first letter of username from props', async () => { diff --git a/packages/manager/src/components/BetaChip/BetaChip.test.tsx b/packages/manager/src/components/BetaChip/BetaChip.test.tsx index 39d28178640..69d7d499fe2 100644 --- a/packages/manager/src/components/BetaChip/BetaChip.test.tsx +++ b/packages/manager/src/components/BetaChip/BetaChip.test.tsx @@ -17,7 +17,7 @@ describe('BetaChip', () => { const { getByTestId } = renderWithTheme(); const betaChip = getByTestId('betaChip'); expect(betaChip).toBeInTheDocument(); - expect(betaChip).toHaveStyle('background-color: rgb(16, 138, 214)'); + expect(betaChip).toHaveStyle('background-color: #108ad6'); }); it('triggers an onClick callback', () => { diff --git a/packages/manager/src/components/DescriptionList/DescriptionList.test.tsx b/packages/manager/src/components/DescriptionList/DescriptionList.test.tsx index 6fc2fd2fe20..477d27088f0 100644 --- a/packages/manager/src/components/DescriptionList/DescriptionList.test.tsx +++ b/packages/manager/src/components/DescriptionList/DescriptionList.test.tsx @@ -32,7 +32,7 @@ describe('Description List', () => { it('has it title bolded', () => { const { getByText } = renderWithTheme(); const title = getByText('Random title'); - expect(title).toHaveStyle('font-family: "LatoWebBold",sans-serif'); + expect(title).toHaveStyle('font-family: LatoWebBold, sans-serif'); }); it('renders a column by default', () => { diff --git a/packages/manager/src/components/HighlightedMarkdown/__snapshots__/HighlightedMarkdown.test.tsx.snap b/packages/manager/src/components/HighlightedMarkdown/__snapshots__/HighlightedMarkdown.test.tsx.snap index 238b90d44c9..09a0177c34b 100644 --- a/packages/manager/src/components/HighlightedMarkdown/__snapshots__/HighlightedMarkdown.test.tsx.snap +++ b/packages/manager/src/components/HighlightedMarkdown/__snapshots__/HighlightedMarkdown.test.tsx.snap @@ -4,52 +4,52 @@ exports[`HighlightedMarkdown component > should highlight text consistently 1`]

-

- Some markdown -

- + > +

+ Some markdown +

+ -
-    
-      
-        const
-      
-       x = 
-      
+      
         
-          function
+          const
         
-        (
+         x = 
         
-        ) 
-      
-      { 
-      
-        return
-      
-       
-      
-        true
-      
-      ; }
+          class="hljs-function"
+        >
+          
+            function
+          
+          (
+          
+          ) 
+        
+        { 
+        
+          return
+        
+         
+        
+          true
+        
+        ; }
 
-    
-  
-

+ + +

`; diff --git a/packages/manager/src/components/Notice/Notice.test.tsx b/packages/manager/src/components/Notice/Notice.test.tsx index e7d536cd907..029e9d86d10 100644 --- a/packages/manager/src/components/Notice/Notice.test.tsx +++ b/packages/manager/src/components/Notice/Notice.test.tsx @@ -11,8 +11,8 @@ describe('Notice Component', () => { const notice = container.firstChild; expect(notice).toHaveStyle('margin-bottom: 24px'); - expect(notice).toHaveStyle('margin-left: 0'); - expect(notice).toHaveStyle('margin-top: 0'); + expect(notice).toHaveStyle('margin-left: 0px'); + expect(notice).toHaveStyle('margin-top: 0px'); }); it('renders with text', () => { diff --git a/packages/manager/src/components/Tabs/Tab.test.tsx b/packages/manager/src/components/Tabs/Tab.test.tsx index 6463053b864..4dc53cd77da 100644 --- a/packages/manager/src/components/Tabs/Tab.test.tsx +++ b/packages/manager/src/components/Tabs/Tab.test.tsx @@ -20,7 +20,7 @@ describe('Tab Component', () => { expect(tabElement).toHaveStyle(` display: inline-flex; - color: rgb(0, 156, 222); + color: #0174bc; `); }); diff --git a/packages/manager/src/components/TextTooltip/TextTooltip.test.tsx b/packages/manager/src/components/TextTooltip/TextTooltip.test.tsx index 301c5787ca5..ba592caabed 100644 --- a/packages/manager/src/components/TextTooltip/TextTooltip.test.tsx +++ b/packages/manager/src/components/TextTooltip/TextTooltip.test.tsx @@ -56,7 +56,7 @@ describe('TextTooltip', () => { const displayText = getByText(props.displayText); - expect(displayText).toHaveStyle('color: rgb(0, 156, 222)'); + expect(displayText).toHaveStyle('color: #0174bc'); expect(displayText).toHaveStyle('font-size: 18px'); }); diff --git a/packages/manager/src/features/Databases/DatabaseCreate/DatabaseCreate.test.tsx b/packages/manager/src/features/Databases/DatabaseCreate/DatabaseCreate.test.tsx index 40b0bf1c6ce..eee0966bf78 100644 --- a/packages/manager/src/features/Databases/DatabaseCreate/DatabaseCreate.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseCreate/DatabaseCreate.test.tsx @@ -24,7 +24,9 @@ describe('Database Create', () => { const { getAllByTestId, getAllByText } = renderWithTheme( ); - await waitForElementToBeRemoved(getAllByTestId(loadingTestId)); + await waitForElementToBeRemoved(getAllByTestId(loadingTestId), { + timeout: 10_000, + }); getAllByText('Cluster Label'); getAllByText('Database Engine'); diff --git a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.test.tsx b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.test.tsx index a7230c71e9f..d4c3f11d44d 100644 --- a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.test.tsx @@ -1,4 +1,4 @@ -import { screen, within } from '@testing-library/react'; +import { screen, waitFor, within } from '@testing-library/react'; import { fireEvent } from '@testing-library/react'; import { waitForElementToBeRemoved } from '@testing-library/react'; import { DateTime } from 'luxon'; @@ -71,6 +71,7 @@ describe('Database Table Row', () => { describe('Database Table', () => { it('should render database landing table with items', async () => { + const database = databaseInstanceFactory.build({ status: 'active' }); const mockAccount = accountFactory.build({ capabilities: [managedDBBetaCapability], }); @@ -81,32 +82,25 @@ describe('Database Table', () => { ); server.use( http.get(databaseInstancesEndpoint, () => { - const databases = databaseInstanceFactory.buildList(1, { - status: 'active', - }); - return HttpResponse.json(makeResourcePage(databases)); + return HttpResponse.json(makeResourcePage([database])); }) ); - const { getAllByText, getByTestId, queryAllByText } = renderWithTheme( - - ); + const { getByText } = renderWithTheme(); - // Loading state should render - expect(getByTestId(loadingTestId)).toBeInTheDocument(); - - await waitForElementToBeRemoved(getByTestId(loadingTestId)); + // wait for API data to load + await waitFor(() => expect(getByText(database.label)).toBeVisible(), { + timeout: 10_000, + }); + expect(getByText('Active')).toBeVisible(); // Static text and table column headers - getAllByText('Cluster Label'); - getAllByText('Status'); - getAllByText('Configuration'); - getAllByText('Engine'); - getAllByText('Region'); - getAllByText('Created'); - - // Check to see if the mocked API data rendered in the table - queryAllByText('Active'); + expect(getByText('Cluster Label')).toBeVisible(); + expect(getByText('Status')).toBeVisible(); + expect(getByText('Configuration')).toBeVisible(); + expect(getByText('Engine')).toBeVisible(); + expect(getByText('Region')).toBeVisible(); + expect(getByText('Created')).toBeVisible(); }); it('should render database landing with empty state', async () => { diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/HAControlPlane.test.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/HAControlPlane.test.tsx index b8f995c02f1..94968d34b79 100644 --- a/packages/manager/src/features/Kubernetes/CreateCluster/HAControlPlane.test.tsx +++ b/packages/manager/src/features/Kubernetes/CreateCluster/HAControlPlane.test.tsx @@ -1,4 +1,4 @@ -import { fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; import { UNKNOWN_PRICE } from 'src/utilities/pricing/constants'; @@ -42,11 +42,11 @@ describe('HAControlPlane', () => { await findByText(/\$60\.00/); }); - it('should call the handleChange function on change', () => { + it('should call the handleChange function on change', async () => { const { getByTestId } = renderWithTheme(); const haRadioButton = getByTestId('ha-radio-button-yes'); - fireEvent.click(haRadioButton); + await userEvent.click(haRadioButton); expect(props.setHighAvailability).toHaveBeenCalled(); }); }); diff --git a/packages/manager/src/features/Linodes/CloneLanding/Disks.test.tsx b/packages/manager/src/features/Linodes/CloneLanding/Disks.test.tsx index dc55a90af9e..396cc774603 100644 --- a/packages/manager/src/features/Linodes/CloneLanding/Disks.test.tsx +++ b/packages/manager/src/features/Linodes/CloneLanding/Disks.test.tsx @@ -33,7 +33,7 @@ describe('Disks', () => { const { getByTestId } = render(wrapWithTheme()); disks.forEach((eachDisk) => { const checkbox = getByTestId(`checkbox-${eachDisk.id}`).parentNode; - fireEvent.click(checkbox as any); + fireEvent.click(checkbox!); expect(mockHandleSelect).toHaveBeenCalledWith(eachDisk.id); }); }); @@ -47,10 +47,10 @@ describe('Disks', () => { }); it('checks the disk if the associated config is selected', () => { - const { getByTestId } = render( + const { getByRole } = render( wrapWithTheme() ); - const checkbox: any = getByTestId('checkbox-19040624').firstElementChild; - expect(checkbox).toHaveAttribute('checked'); + const checkbox = getByRole('checkbox', { name: '512 MB Swap Image' }); + expect(checkbox).toBeChecked(); }); }); diff --git a/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.test.tsx b/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.test.tsx index eb193d24815..a500440cfb3 100644 --- a/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.test.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.test.tsx @@ -69,7 +69,7 @@ describe('VPC', () => { it('renders VPC IPv4, NAT checkboxes, and IP Ranges inputs when a subnet is selected', async () => { const { - getByLabelText, + getByRole, getByText, } = renderWithThemeAndHookFormContext({ component: , @@ -82,13 +82,15 @@ describe('VPC', () => { }); expect( - getByLabelText( - 'Auto-assign a VPC IPv4 address for this Linode in the VPC' - ) + getByRole('checkbox', { + name: 'Auto-assign a VPC IPv4 address for this Linode in the VPC', + }) ).toBeInTheDocument(); expect( - getByLabelText('Assign a public IPv4 address for this Linode') + getByRole('checkbox', { + name: 'Assign a public IPv4 address for this Linode', + }) ).toBeInTheDocument(); expect(getByText('Assign additional IPv4 ranges')).toBeInTheDocument(); @@ -96,7 +98,7 @@ describe('VPC', () => { it('should check the VPC IPv4 if a "ipv4.vpc" is null/undefined', async () => { const { - getByLabelText, + getByRole, } = renderWithThemeAndHookFormContext({ component: , useFormOptions: { @@ -112,15 +114,16 @@ describe('VPC', () => { }); expect( - getByLabelText( - 'Auto-assign a VPC IPv4 address for this Linode in the VPC' - ) + getByRole('checkbox', { + name: 'Auto-assign a VPC IPv4 address for this Linode in the VPC', + }) ).toBeChecked(); }); it('should uncheck the VPC IPv4 if a "ipv4.vpc" is a string value and show the VPC IP TextField', async () => { const { getByLabelText, + getByRole, } = renderWithThemeAndHookFormContext({ component: , useFormOptions: { @@ -132,9 +135,9 @@ describe('VPC', () => { }); expect( - getByLabelText( - 'Auto-assign a VPC IPv4 address for this Linode in the VPC' - ) + getByRole('checkbox', { + name: 'Auto-assign a VPC IPv4 address for this Linode in the VPC', + }) ).not.toBeChecked(); expect(getByLabelText('VPC IPv4 (required)')).toBeVisible(); diff --git a/packages/manager/src/features/Linodes/LinodeCreate/index.test.tsx b/packages/manager/src/features/Linodes/LinodeCreate/index.test.tsx index 7e53195eacc..dbde52b4812 100644 --- a/packages/manager/src/features/Linodes/LinodeCreate/index.test.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreate/index.test.tsx @@ -23,10 +23,10 @@ describe('Linode Create', () => { }); it('Should not render the region select when creating from a backup', () => { - const { queryByText } = renderWithTheme(, { + const { queryByLabelText } = renderWithTheme(, { MemoryRouter: { initialEntries: ['/linodes/create?type=Backups'] }, }); - expect(queryByText('Region')).toBeNull(); + expect(queryByLabelText('Region')).toBeNull(); }); }); diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/LinodeIPAddressRow.test.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/LinodeIPAddressRow.test.tsx index cb5dd2b9beb..12c95cd82e9 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/LinodeIPAddressRow.test.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/LinodeIPAddressRow.test.tsx @@ -1,4 +1,4 @@ -import { fireEvent } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import * as React from 'react'; import { LinodeConfigInterfaceFactoryWithVPC } from 'src/factories/linodeConfigInterfaceFactory'; @@ -10,7 +10,9 @@ import { import { PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT } from 'src/features/Linodes/PublicIpsUnassignedTooltip'; import { renderWithTheme, wrapWithTableBody } from 'src/utilities/testHelpers'; -import { IPAddressRowHandlers, LinodeIPAddressRow } from './LinodeIPAddressRow'; +import { LinodeIPAddressRow } from './LinodeIPAddressRow'; + +import type { IPAddressRowHandlers} from './LinodeIPAddressRow'; const ips = linodeIPFactory.build(); const ipDisplay = ipResponseToDisplayRows(ips)[0]; @@ -27,8 +29,8 @@ const handlers: IPAddressRowHandlers = { }; describe('LinodeIPAddressRow', () => { - it('should render a Linode IP Address row', () => { - const { getAllByText } = renderWithTheme( + it('should render a Linode IP Address row', async () => { + const { getAllByText, getByLabelText } = renderWithTheme( wrapWithTableBody( { ) ); + // open the action menu + await userEvent.click( + getByLabelText('Action menu for IP Address [object Object]') + ); + getAllByText(ipDisplay.address); getAllByText(ipDisplay.type); getAllByText(ipDisplay.gateway); @@ -70,7 +77,7 @@ describe('LinodeIPAddressRow', () => { }); it('should disable the row if disabled is true and display a tooltip', async () => { - const { findByRole, getByTestId } = renderWithTheme( + const { getAllByLabelText, getByLabelText, getByTestId } = renderWithTheme( wrapWithTableBody( { ) ); - const deleteBtn = getByTestId('action-menu-item-delete'); - expect(deleteBtn).toHaveAttribute('aria-disabled', 'true'); - fireEvent.mouseEnter(deleteBtn); - const publicIpsUnassignedTooltip = await findByRole('tooltip'); - expect(publicIpsUnassignedTooltip).toContainHTML( - PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT + // open the action menu + await userEvent.click( + getByLabelText('Action menu for IP Address [object Object]') ); - const editRDNSBtn = getByTestId('action-menu-item-edit-rdns'); + const deleteBtn = getByTestId('Delete'); + expect(deleteBtn).toHaveAttribute('aria-disabled', 'true'); + + const editRDNSBtn = getByTestId('Edit RDNS'); expect(editRDNSBtn).toHaveAttribute('aria-disabled', 'true'); - fireEvent.mouseEnter(editRDNSBtn); - const publicIpsUnassignedTooltip2 = await findByRole('tooltip'); - expect(publicIpsUnassignedTooltip2).toContainHTML( - PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT - ); + expect(getAllByLabelText(PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT)).toHaveLength(2); }); - it('should not disable the row if disabled is false', () => { - const { getAllByRole } = renderWithTheme( + it('should not disable the row if disabled is false', async () => { + const { getByLabelText, getByTestId } = renderWithTheme( wrapWithTableBody( { ) ); - const buttons = getAllByRole('button'); - const deleteBtn = buttons[1]; - expect(deleteBtn).not.toHaveAttribute('aria-disabled', 'true'); + // open the action menu + await userEvent.click( + getByLabelText('Action menu for IP Address [object Object]') + ); + + expect(getByTestId('Delete')).toBeEnabled(); - const editRDNSBtn = buttons[3]; - expect(editRDNSBtn).not.toHaveAttribute('aria-disabled', 'true'); + expect(getByTestId('Edit RDNS')).toBeEnabled(); }); }); diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx index 2255e3115ec..dda6abc4339 100644 --- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx +++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx @@ -212,9 +212,9 @@ describe('VPCPanel', () => { await waitFor(() => { expect( - wrapper.getByLabelText( - 'Auto-assign a VPC IPv4 address for this Linode in the VPC' - ) + wrapper.getByRole('checkbox', { + name: 'Auto-assign a VPC IPv4 address for this Linode in the VPC', + }) ).not.toBeChecked(); // Using regex here to account for the "(required)" indicator. expect(wrapper.getByLabelText(/^VPC IPv4.*/)).toHaveValue('10.0.4.3'); @@ -244,7 +244,9 @@ describe('VPCPanel', () => { await waitFor(() => { expect( - wrapper.getByLabelText('Assign a public IPv4 address for this Linode') + wrapper.getByRole('checkbox', { + name: 'Assign a public IPv4 address for this Linode', + }) ).toBeChecked(); }); }); diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerConfigPanel.test.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerConfigPanel.test.tsx index fa06be32953..064e76f616b 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerConfigPanel.test.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerConfigPanel.test.tsx @@ -85,6 +85,7 @@ const proxyProtocol = 'Proxy Protocol'; describe('NodeBalancerConfigPanel', () => { it('renders the NodeBalancerConfigPanel', () => { const { + getAllByLabelText, getByLabelText, getByText, queryByLabelText, @@ -101,7 +102,13 @@ describe('NodeBalancerConfigPanel', () => { expect(getByLabelText('Label')).toBeVisible(); expect(getByLabelText('IP Address')).toBeVisible(); expect(getByLabelText('Weight')).toBeVisible(); - expect(getByLabelText('Port')).toBeVisible(); + + const portTextFields = getAllByLabelText('Port'); + expect(portTextFields).toHaveLength(2); // There is a port field for the config and a port field for the one node + for (const field of portTextFields) { + expect(field).toBeVisible(); + } + expect(getByText('Listen on this port.')).toBeVisible(); expect(getByText('Active Health Checks')).toBeVisible(); expect( diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.test.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.test.tsx index d82c1156bf9..d4480664a67 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.test.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.test.tsx @@ -44,13 +44,15 @@ describe('NodeBalancerConfigurations', () => { }) ); - const { getByLabelText, getByTestId, getByText } = renderWithTheme( - , - { - MemoryRouter: memoryRouter, - routePath, - } - ); + const { + getAllByLabelText, + getByLabelText, + getByTestId, + getByText, + } = renderWithTheme(, { + MemoryRouter: memoryRouter, + routePath, + }); expect(getByTestId(loadingTestId)).toBeInTheDocument(); @@ -65,7 +67,11 @@ describe('NodeBalancerConfigurations', () => { expect(getByLabelText('Label')).toBeInTheDocument(); expect(getByLabelText('IP Address')).toBeInTheDocument(); expect(getByLabelText('Weight')).toBeInTheDocument(); - expect(getByLabelText('Port')).toBeInTheDocument(); + const portTextFields = getAllByLabelText('Port'); + expect(portTextFields).toHaveLength(2); // There is a port field for the config and a port field for the one node + for (const field of portTextFields) { + expect(field).toBeInTheDocument(); + } expect(getByText('Listen on this port.')).toBeInTheDocument(); expect(getByText('Active Health Checks')).toBeInTheDocument(); expect( diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerActionMenu.test.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerActionMenu.test.tsx index e950688d3d4..61407c83bf6 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerActionMenu.test.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerActionMenu.test.tsx @@ -12,25 +12,31 @@ const props = { }; describe('NodeBalancerActionMenu', () => { - afterEach(() => { - vi.resetAllMocks(); - }); - - it('renders the NodeBalancerActionMenu', () => { - const { getByText } = renderWithTheme( + it('renders the NodeBalancerActionMenu', async () => { + const { getByLabelText, getByText } = renderWithTheme( ); + // Open the Action Menu + await userEvent.click( + getByLabelText(`Action menu for NodeBalancer ${props.nodeBalancerId}`) + ); + expect(getByText('Configurations')).toBeVisible(); expect(getByText('Settings')).toBeVisible(); expect(getByText('Delete')).toBeVisible(); }); it('triggers the action to delete the NodeBalancer', async () => { - const { getByText } = renderWithTheme( + const { getByLabelText, getByText } = renderWithTheme( ); + // Open the Action Menu + await userEvent.click( + getByLabelText(`Action menu for NodeBalancer ${props.nodeBalancerId}`) + ); + const deleteButton = getByText('Delete'); await userEvent.click(deleteButton); expect(props.toggleDialog).toHaveBeenCalled(); diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerTableRow.test.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerTableRow.test.tsx index 42d3acaad73..f09fae2088d 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerTableRow.test.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancerTableRow.test.tsx @@ -20,11 +20,19 @@ describe('NodeBalancerTableRow', () => { vi.resetAllMocks(); }); - it('renders the NodeBalancer table row', () => { - const { getByText } = renderWithTheme(); + it('renders the NodeBalancer table row', async () => { + const { getByLabelText, getByText } = renderWithTheme( + + ); expect(getByText('nodebalancer-id-1')).toBeVisible(); expect(getByText('0.0.0.0')).toBeVisible(); + + // Open the Action Menu + await userEvent.click( + getByLabelText(`Action menu for NodeBalancer ${props.id}`) + ); + expect(getByText('Configurations')).toBeVisible(); expect(getByText('Settings')).toBeVisible(); expect(getByText('Delete')).toBeVisible(); diff --git a/packages/manager/src/features/Profile/OAuthClients/CreateOAuthClientDrawer.test.tsx b/packages/manager/src/features/Profile/OAuthClients/CreateOAuthClientDrawer.test.tsx index 59d5955191f..1697d16479f 100644 --- a/packages/manager/src/features/Profile/OAuthClients/CreateOAuthClientDrawer.test.tsx +++ b/packages/manager/src/features/Profile/OAuthClients/CreateOAuthClientDrawer.test.tsx @@ -27,11 +27,11 @@ describe('Create API Token Drawer', () => { getByText('Cancel'); }); it('Should show client side validation errors', async () => { - const { getByText } = renderWithTheme( + const { getByRole, getByText } = renderWithTheme( ); - const submit = getByText('Create'); + const submit = getByRole('button', { name: 'Create' }); await userEvent.click(submit); @@ -47,7 +47,7 @@ describe('Create API Token Drawer', () => { }) ); - const { getAllByTestId, getByText } = renderWithTheme( + const { getAllByTestId, getByRole } = renderWithTheme( ); @@ -56,7 +56,7 @@ describe('Create API Token Drawer', () => { const labelField = textFields[0]; const callbackUrlField = textFields[1]; - const submit = getByText('Create'); + const submit = getByRole('button', { name: 'Create' }); await userEvent.type(labelField, 'my-oauth-client'); await userEvent.type(callbackUrlField, 'http://localhost:3000'); diff --git a/packages/manager/src/features/Volumes/VolumeCreate.test.tsx b/packages/manager/src/features/Volumes/VolumeCreate.test.tsx index 0e611ed9fb7..57352b996da 100644 --- a/packages/manager/src/features/Volumes/VolumeCreate.test.tsx +++ b/packages/manager/src/features/Volumes/VolumeCreate.test.tsx @@ -55,6 +55,6 @@ describe('VolumeCreate', () => { flags: { blockStorageEncryption: true }, }); - await findByText(encryptVolumeSectionHeader); + await findByText(encryptVolumeSectionHeader, {}, { timeout: 5_000 }); }); }); diff --git a/packages/manager/src/utilities/omittedProps.test.tsx b/packages/manager/src/utilities/omittedProps.test.tsx index 56a046e1220..b8921875e9e 100644 --- a/packages/manager/src/utilities/omittedProps.test.tsx +++ b/packages/manager/src/utilities/omittedProps.test.tsx @@ -35,7 +35,7 @@ describe('omittedProps utility', () => { expect(component).not.toHaveAttribute('extraProp'); expect(component).not.toHaveAttribute('anotherProp'); - expect(component).toHaveStyle('color: rgb(255, 0, 0)'); + expect(component).toHaveStyle('color: red'); }); }); diff --git a/packages/manager/vite.config.ts b/packages/manager/vite.config.ts index afab3254c56..296323066bc 100644 --- a/packages/manager/vite.config.ts +++ b/packages/manager/vite.config.ts @@ -37,8 +37,7 @@ export default defineConfig({ 'src/**/*.utils.{js,jsx,ts,tsx}', ], }, - pool: 'forks', - environment: 'jsdom', + environment: 'happy-dom', globals: true, setupFiles: './src/testSetup.ts', }, diff --git a/packages/ui/.changeset/pr-11085-tests-1728657169966.md b/packages/ui/.changeset/pr-11085-tests-1728657169966.md new file mode 100644 index 00000000000..107ae6b952a --- /dev/null +++ b/packages/ui/.changeset/pr-11085-tests-1728657169966.md @@ -0,0 +1,5 @@ +--- +"@linode/ui": Tests +--- + +Use `happy-dom` instead of `jsdom` in unit tests ([#11085](https://github.com/linode/manager/pull/11085)) diff --git a/packages/ui/src/components/BetaChip/BetaChip.test.tsx b/packages/ui/src/components/BetaChip/BetaChip.test.tsx index c4da709edd5..4f922765477 100644 --- a/packages/ui/src/components/BetaChip/BetaChip.test.tsx +++ b/packages/ui/src/components/BetaChip/BetaChip.test.tsx @@ -18,7 +18,7 @@ describe('BetaChip', () => { const { getByTestId } = render(); const betaChip = getByTestId('betaChip'); expect(betaChip).toBeInTheDocument(); - expect(betaChip).toHaveStyle('background-color: rgb(25, 118, 210)'); + expect(betaChip).toHaveStyle('background-color: #1976d2'); }); it('triggers an onClick callback', () => { diff --git a/packages/ui/vitest.config.ts b/packages/ui/vitest.config.ts index 95754d431b5..c4ce34c1442 100644 --- a/packages/ui/vitest.config.ts +++ b/packages/ui/vitest.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - environment: 'jsdom', + environment: 'happy-dom', setupFiles: './testSetup.ts', }, }); diff --git a/yarn.lock b/yarn.lock index 39b3c3fa612..7fef5d8b381 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2922,13 +2922,6 @@ acorn@^8.12.0, acorn@^8.12.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== -agent-base@^7.0.2, agent-base@^7.1.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" - integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== - dependencies: - debug "^4.3.4" - aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -4015,13 +4008,6 @@ css.escape@^1.5.1: resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== -cssstyle@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-4.1.0.tgz#161faee382af1bafadb6d3867a92a19bcb4aea70" - integrity sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA== - dependencies: - rrweb-cssom "^0.7.1" - csstype@^2.5.7: version "2.6.21" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" @@ -4186,14 +4172,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-urls@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-5.0.0.tgz#2f76906bce1824429ffecb6920f45a0b30f00dde" - integrity sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg== - dependencies: - whatwg-mimetype "^4.0.0" - whatwg-url "^14.0.0" - data-view-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" @@ -4233,13 +4211,6 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@~4.3.6: - version "4.3.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - debug@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4247,16 +4218,18 @@ debug@^3.1.0: dependencies: ms "^2.1.1" +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@~4.3.6: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decimal.js-light@^2.4.1: version "2.5.1" resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== -decimal.js@^10.4.3: - version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== - decode-named-character-reference@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz#daabac9690874c394c81e4162a0304b35d824f0e" @@ -4483,7 +4456,7 @@ enquirer@^2.3.5, enquirer@^2.3.6: ansi-colors "^4.1.1" strip-ansi "^6.0.1" -entities@^4.4.0: +entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -5815,6 +5788,15 @@ graphql@^16.8.1: resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== +happy-dom@^15.7.4: + version "15.7.4" + resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-15.7.4.tgz#05aade59c1d307336001b7004c76dfc6a829f220" + integrity sha512-r1vadDYGMtsHAAsqhDuk4IpPvr6N8MGKy5ntBo7tSdim+pWDxus2PNqOcOt8LuDZ4t3KJHE+gCuzupcx/GKnyQ== + dependencies: + entities "^4.5.0" + webidl-conversions "^7.0.0" + whatwg-mimetype "^3.0.0" + has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -5936,13 +5918,6 @@ hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react- dependencies: react-is "^16.7.0" -html-encoding-sniffer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz#696df529a7cfd82446369dc5193e590a3735b448" - integrity sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ== - dependencies: - whatwg-encoding "^3.1.1" - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -5972,14 +5947,6 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" -http-proxy-agent@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" - integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== - dependencies: - agent-base "^7.1.0" - debug "^4.3.4" - http-signature@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" @@ -5989,14 +5956,6 @@ http-signature@~1.4.0: jsprim "^2.0.2" sshpk "^1.18.0" -https-proxy-agent@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" - integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== - dependencies: - agent-base "^7.0.2" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -6024,13 +5983,6 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -6355,11 +6307,6 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -6572,33 +6519,6 @@ jsdoc-type-pratt-parser@^4.0.0: resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== -jsdom@^24.1.1: - version "24.1.3" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.1.3.tgz#88e4a07cb9dd21067514a619e9f17b090a394a9f" - integrity sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ== - dependencies: - cssstyle "^4.0.1" - data-urls "^5.0.0" - decimal.js "^10.4.3" - form-data "^4.0.0" - html-encoding-sniffer "^4.0.0" - http-proxy-agent "^7.0.2" - https-proxy-agent "^7.0.5" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.12" - parse5 "^7.1.2" - rrweb-cssom "^0.7.1" - saxes "^6.0.0" - symbol-tree "^3.2.4" - tough-cookie "^4.1.4" - w3c-xmlserializer "^5.0.0" - webidl-conversions "^7.0.0" - whatwg-encoding "^3.1.1" - whatwg-mimetype "^4.0.0" - whatwg-url "^14.0.0" - ws "^8.18.0" - xml-name-validator "^5.0.0" - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -7744,11 +7664,6 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" -nwsapi@^2.2.12: - version "2.2.12" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.12.tgz#fb6af5c0ec35b27b4581eb3bbad34ec9e5c696f8" - integrity sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w== - object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -7955,13 +7870,6 @@ parse-json@^5.0.0, parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== - dependencies: - entities "^4.4.0" - parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -8234,7 +8142,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: +punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -8861,11 +8769,6 @@ rollup@^4.19.0, rollup@^4.20.0: "@rollup/rollup-win32-x64-msvc" "4.22.4" fsevents "~2.3.2" -rrweb-cssom@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz#c73451a484b86dd7cfb1e0b2898df4b703183e4b" - integrity sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg== - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -8916,7 +8819,7 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -8926,13 +8829,6 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== -saxes@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" - integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== - dependencies: - xmlchars "^2.2.0" - scheduler@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4" @@ -9484,11 +9380,6 @@ symbol-observable@^1.0.4: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -9671,13 +9562,6 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" -tr46@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-5.0.0.tgz#3b46d583613ec7283020d79019f1335723801cec" - integrity sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g== - dependencies: - punycode "^2.3.1" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -10181,13 +10065,6 @@ vitest@^2.1.1: vite-node "2.1.1" why-is-node-running "^2.3.0" -w3c-xmlserializer@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" - integrity sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA== - dependencies: - xml-name-validator "^5.0.0" - warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" @@ -10215,30 +10092,15 @@ webpack-virtual-modules@^0.6.2: resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" integrity sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ== -whatwg-encoding@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" - integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ== - dependencies: - iconv-lite "0.6.3" - whatwg-fetch@>=0.10.0: version "3.6.20" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70" integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg== -whatwg-mimetype@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a" - integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg== - -whatwg-url@^14.0.0: - version "14.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-14.0.0.tgz#00baaa7fd198744910c4b1ef68378f2200e4ceb6" - integrity sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw== - dependencies: - tr46 "^5.0.0" - webidl-conversions "^7.0.0" +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== whatwg-url@^5.0.0: version "5.0.0" @@ -10382,16 +10244,11 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^8.18.0, ws@^8.2.3: +ws@^8.2.3: version "8.18.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -xml-name-validator@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" - integrity sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg== - xml2js@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" @@ -10410,11 +10267,6 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"