From ca883f9cfd8151fb84f888adfd4cc5873f12c636 Mon Sep 17 00:00:00 2001 From: nicolethoen Date: Mon, 30 Mar 2026 16:37:19 -0400 Subject: [PATCH 1/3] chore: update unit tests to RTL --- __mocks__/domPolyfills.js | 26 ++++ before-tests.js | 6 - jest-setup-framework.js | 1 + package.json | 6 +- packages/module/package.json | 1 + .../__tests__/MarkdownCopyClipboard.spec.tsx | 36 ++++-- .../__tests__/QuickStartCatalog.spec.tsx | 56 +++++---- .../catalog/__tests__/QuickStartTile.spec.tsx | 70 +++++++---- .../QuickStartTileDescription.spec.tsx | 60 +++++---- .../__tests__/QuickStartConclusion.spec.tsx | 107 ++++++++-------- .../__tests__/QuickStartContent.spec.tsx | 75 ++++++++---- .../__tests__/QuickStartFooter.spec.tsx | 115 +++++++----------- .../__tests__/QuickStartTaskHeader.spec.tsx | 51 ++++---- .../__tests__/QuickStartTaskReview.spec.tsx | 64 ++++++---- .../__tests__/QuickStartTasks.spec.tsx | 101 ++++++++------- test-setup.js | 6 +- yarn.lock | 53 ++++++++ 17 files changed, 480 insertions(+), 354 deletions(-) create mode 100644 __mocks__/domPolyfills.js create mode 100644 jest-setup-framework.js diff --git a/__mocks__/domPolyfills.js b/__mocks__/domPolyfills.js new file mode 100644 index 00000000..9679ae30 --- /dev/null +++ b/__mocks__/domPolyfills.js @@ -0,0 +1,26 @@ +/* eslint-disable */ + +// Polyfill for Element.prototype.getRootNode (missing in older jsdom) +if (!Element.prototype.getRootNode) { + Element.prototype.getRootNode = function (options) { + var node = this; + while (node.parentNode) { + node = node.parentNode; + } + return node; + }; +} + +// Polyfill for Element.prototype.closest (missing in older jsdom) +if (!Element.prototype.closest) { + Element.prototype.closest = function (selector) { + var el = this; + while (el) { + if (el.matches && el.matches(selector)) { + return el; + } + el = el.parentElement; + } + return null; + }; +} diff --git a/before-tests.js b/before-tests.js index aeea426c..5c3f6e20 100644 --- a/before-tests.js +++ b/before-tests.js @@ -1,9 +1,3 @@ /* eslint-env node */ -import { configure } from 'enzyme'; -import * as Adapter from 'enzyme-adapter-react-16'; - import 'url-search-params-polyfill'; - -// http://airbnb.io/enzyme/docs/installation/index.html#working-with-react-16 -configure({ adapter: new Adapter() }); diff --git a/jest-setup-framework.js b/jest-setup-framework.js new file mode 100644 index 00000000..09326480 --- /dev/null +++ b/jest-setup-framework.js @@ -0,0 +1 @@ +require('@testing-library/jest-dom'); diff --git a/package.json b/package.json index 564baeb7..e090f746 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,8 @@ "./__mocks__/serverFlags.js", "./__mocks__/mutationObserver.js", "./__mocks__/websocket.js", - "./before-tests.js" + "./before-tests.js", + "./__mocks__/domPolyfills.js" ], "coverageDirectory": "__coverage__", "coverageReporters": [ @@ -115,7 +116,8 @@ "src/**/*.{js,jsx,ts,tsx}", "!**/node_modules/**" ], - "resolver": "./jest-resolver.js" + "resolver": "./jest-resolver.js", + "setupTestFrameworkScriptFile": "./jest-setup-framework.js" }, "engines": { "node": ">=18.0.0" diff --git a/packages/module/package.json b/packages/module/package.json index 93a5c4e7..1687b087 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -66,6 +66,7 @@ "@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.1.0", + "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^13.4.0", "@types/dompurify": "^3.0.5", "@types/enzyme": "^3.10.7", diff --git a/packages/module/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx b/packages/module/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx index f727f517..bbd534d1 100644 --- a/packages/module/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx +++ b/packages/module/src/ConsoleShared/src/components/markdown-extensions/__tests__/MarkdownCopyClipboard.spec.tsx @@ -1,24 +1,38 @@ -import { shallow } from 'enzyme'; -import MarkdownCopyClipboard, { CopyClipboard } from '../MarkdownCopyClipboard'; +import { render } from '@testing-library/react'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '@quickstarts/utils/quick-start-context'; +import MarkdownCopyClipboard from '../MarkdownCopyClipboard'; +import { MARKDOWN_COPY_BUTTON_ID } from '../const'; import { htmlDocumentForCopyClipboard } from './test-data'; +const contextValues = { + ...QuickStartContextDefaults, + getResource: (key: string) => key, +}; + describe('MarkdownCopyClipboard', () => { beforeAll(() => { document.body.innerHTML = htmlDocumentForCopyClipboard; }); + it('should render null if no element is found', () => { - const wrapper = shallow( - , + const { container } = render( + + + , ); - expect(wrapper.isEmptyRender()).toBe(true); - expect(wrapper.find(CopyClipboard).exists()).toBe(false); + expect(container.firstChild).toBeNull(); }); - it('should render null if no element is found', () => { - const wrapper = shallow( - , + it('should render copy targets when rootSelector matches buttons in the document', () => { + render( + + + , ); - expect(wrapper.isEmptyRender()).toBe(false); - expect(wrapper.find(CopyClipboard).exists()).toBe(true); + const elements = document.querySelectorAll(`#copy-markdown-1 [${MARKDOWN_COPY_BUTTON_ID}]`); + expect(elements).toHaveLength(2); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx index 52517168..adee908a 100644 --- a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx @@ -1,34 +1,40 @@ -import { Gallery, Card } from '@patternfly/react-core'; -import { shallow } from 'enzyme'; -import { EmptyBox } from '@console/internal/components/utils'; +import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; -import { QuickStartCatalogPage } from '../../QuickStartCatalogPage'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import QuickStartCatalog from '../QuickStartCatalog'; -jest.mock('@console/shared', () => { - const ActualShared = require.requireActual('@console/shared'); - return { - ...ActualShared, - useQueryParams: () => new Map(), - }; -}); +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + allQuickStartStates: {}, + getResource: (key: string) => key, +}; + +const renderWithContext = (props: any) => + render( + + + , + ); describe('QuickStartCatalog', () => { - it('should load an emptybox if no QS exist', () => { - const QuickStartCatalogProps = { quickStarts: [], onClick: jest.fn() }; - const QuickStartCatalogWrapper = shallow(); - expect(QuickStartCatalogWrapper.find(EmptyBox).exists()).toBeTruthy(); + it('should render an empty state if no QS exist', () => { + renderWithContext({ quickStarts: [] }); + // When no quickstarts, the catalog renders no cards + expect(screen.queryByRole('article')).not.toBeInTheDocument(); }); + it('should load a gallery if QS exist', () => { - const QuickStartCatalogProps = { quickStarts: getQuickStarts(), onClick: jest.fn() }; - const QuickStartCatalogWrapper = shallow(); - expect(QuickStartCatalogWrapper.find(Gallery).exists()).toBeTruthy(); - }); - xit('should load galleryItems equal to the number of QS', () => { - const QuickStartCatalogProps = { quickStarts: getQuickStarts(), onClick: jest.fn() }; - const QuickStartCatalogWrapper = shallow(); - const galleryItems = QuickStartCatalogWrapper.find(Card); - expect(galleryItems.exists()).toBeTruthy(); - expect(galleryItems.length).toEqual(getQuickStarts().length); + const quickStarts = getQuickStarts(); + renderWithContext({ quickStarts }); + // Each tile exposes the quick start display name as the title control (link-styled button) + quickStarts.forEach((qs) => { + expect( + screen.getByRole('button', { name: qs.spec.displayName }), + ).toBeInTheDocument(); + }); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx index 885fcf22..793fecbd 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx @@ -1,37 +1,55 @@ -import { Card } from '@patternfly/react-core'; -import { shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; import { QuickStartStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import QuickStartTile from '../QuickStartTile'; -describe('QuickStartTile', () => { - const quickstarts = getQuickStarts(); +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + setActiveQuickStart: jest.fn(), + getResource: (key: string) => key, +}; + +const quickstarts = getQuickStarts(); +const renderWithContext = (props: any) => + render( + + + , + ); + +describe('QuickStartTile', () => { it('should load proper catalog tile without featured property', () => { - const wrapper = shallow( - , - ); - const catalogTile = wrapper.find(Card); - expect(catalogTile.exists()).toBeTruthy(); - expect(catalogTile.hasClass('pf-m-current')).toBe(false); + const quickStart = quickstarts[0]; + renderWithContext({ + quickStart, + status: QuickStartStatus.NOT_STARTED, + onClick: jest.fn(), + isActive: false, + }); + expect( + screen.getByRole('button', { name: quickStart.spec.displayName }), + ).toBeInTheDocument(); + // Status label is omitted for not-started tiles + expect(screen.queryByText('In progress')).not.toBeInTheDocument(); }); it('should load proper catalog tile with featured property', () => { - const wrapper = shallow( - , - ); - const catalogTile = wrapper.find(Card); - expect(catalogTile.exists()).toBeTruthy(); - expect(catalogTile.hasClass('pf-m-current')).toBe(true); + const quickStart = quickstarts[1]; + renderWithContext({ + quickStart, + status: QuickStartStatus.IN_PROGRESS, + onClick: jest.fn(), + isActive: true, + }); + expect( + screen.getByRole('button', { name: quickStart.spec.displayName }), + ).toBeInTheDocument(); + expect(screen.getByText('In progress')).toBeInTheDocument(); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx index 004f19e0..cdd02bf9 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx @@ -1,43 +1,41 @@ -import { Popover } from '@patternfly/react-core'; -import { shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import QuickStartTileDescription from '../QuickStartTileDescription'; -jest.mock('react', () => { - const ActualReact = require.requireActual('react'); - return { - ...ActualReact, - useContext: () => jest.fn(), - }; -}); +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + startQuickStart: jest.fn(), + restartQuickStart: jest.fn(), + getResource: (key: string) => key, +}; -xdescribe('QuickStartCatalog', () => { - beforeEach(() => { - spyOn(React, 'useContext').and.returnValue({ - activeQuickStartID: '', - startQuickStart: () => {}, - restartQuickStart: () => {}, - getResource: (key) => `quickstart~${key}`, - }); - }); +const renderWithContext = (props: any) => + render( + + + , + ); +describe('QuickStartTileDescription', () => { it('should show prerequisites only if provided', () => { - // this quick start does not have prereqs const quickStart = getQuickStarts()[0].spec; - const QuickStartTileDescriptionWrapper = shallow( - , - ); - expect(QuickStartTileDescriptionWrapper.find(Text)).toHaveLength(0); + renderWithContext({ description: quickStart.description }); + expect( + screen.queryByRole('button', { name: 'Show prerequisites' }), + ).not.toBeInTheDocument(); }); - it('shoould render prerequisites inside a popover', () => { + it('should render prerequisites trigger when prerequisite list is non-empty', () => { const quickStart = getQuickStarts()[2].spec; - const QuickStartTileDescriptionWrapper = shallow( - , - ); - expect(QuickStartTileDescriptionWrapper.find(Popover)).toHaveLength(1); + renderWithContext({ + description: quickStart.description, + prerequisites: quickStart.prerequisites, + }); + expect(screen.getByRole('button', { name: 'Show prerequisites' })).toBeInTheDocument(); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx b/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx index 08eb34e3..3034c839 100644 --- a/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx @@ -1,25 +1,22 @@ -import { ComponentProps } from 'react'; -import { Button } from '@patternfly/react-core'; -import { ShallowWrapper, shallow } from 'enzyme'; +import { render, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; -import QuickStartMarkdownView from '../../QuickStartMarkdownView'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartConclusion from '../QuickStartConclusion'; -jest.mock('react', () => { - const ActualReact = require.requireActual('react'); - return { - ...ActualReact, - useContext: () => jest.fn(), - }; -}); - -const i18nNS = 'quickstart'; +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + startQuickStart: jest.fn(), + restartQuickStart: jest.fn(), + getResource: (key: string) => key, +}; -type QuickStartConclusionProps = ComponentProps; -let wrapper: ShallowWrapper; -const props: QuickStartConclusionProps = { +const defaultProps = { tasks: getQuickStartByName('explore-pipelines', allQuickStarts).spec.tasks, allTaskStatuses: [ QuickStartTaskStatus.SUCCESS, @@ -31,52 +28,54 @@ const props: QuickStartConclusionProps = { onQuickStartChange: jest.fn(), }; -xdescribe('QuickStartConclusion', () => { +const renderWithContext = (props = {}) => + render( + + + , + ); + +describe('QuickStartConclusion', () => { beforeEach(() => { - spyOn(React, 'useContext').and.returnValue({ - activeQuickStartID: '', - startQuickStart: () => {}, - restartQuickStart: () => {}, - getResource: (key) => `quickstart~${key}`, - }); - wrapper = shallow(); + jest.clearAllMocks(); }); - it('should render conclusion if there are no failed tasks', () => { - expect(wrapper.find(QuickStartMarkdownView).first().props().content).toEqual('conclusion'); + it('should render conclusion if there are no failed tasks', async () => { + renderWithContext(); + await waitFor(() => { + expect(document.body.textContent).toMatch(/conclusion/); + }); }); - it('should render link for next quick start if nextQuickStart prop is available and there are no failed tasks', () => { - wrapper = shallow( - , - ); - expect(wrapper.find(Button).at(0).props().children).toEqual( - `${i18nNS}~Start Installing the Pipelines Operator quick start`, - ); + it('should render link for next quick start if nextQuickStart prop is available and there are no failed tasks', async () => { + renderWithContext({ + nextQuickStarts: [getQuickStartByName('explore-pipelines', allQuickStarts)], + }); + await waitFor(() => { + expect(document.body.textContent).toMatch(/Start Installing the Pipelines Operator quick start/); + }); }); - it('should not render link for next quick start if nextQuickStart props is not available', () => { - expect(wrapper.find(Button).length).toBe(0); + it('should not render link for next quick start if nextQuickStart props is not available', async () => { + renderWithContext(); + await waitFor(() => { + expect(document.body.textContent).toMatch(/conclusion/); + }); + expect(document.body.textContent).not.toMatch(/Start .* quick start/); }); - it('should not render conclusion, link for next quick start and should render message for retrying if there are failed tasks', () => { - wrapper = shallow( - , - ); - expect(wrapper.find(QuickStartMarkdownView).first().props().content).toEqual( - `${i18nNS}~One or more verifications did not pass during this quick start. Revisit the tasks or the help links, and then try again.`, - ); - expect(wrapper.find(Button).length).toBe(0); + it('should not render conclusion and should render message for retrying if there are failed tasks', async () => { + renderWithContext({ + nextQuickStarts: [getQuickStartByName('explore-pipelines', allQuickStarts)], + allTaskStatuses: [ + QuickStartTaskStatus.FAILED, + QuickStartTaskStatus.SUCCESS, + QuickStartTaskStatus.SUCCESS, + ], + }); + await waitFor(() => { + expect(document.body.textContent).toMatch(/One or more verifications did not pass/); + }); + expect(document.body.textContent).not.toMatch(/Start .* quick start/); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx b/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx index 2b81ecd5..8eef851a 100644 --- a/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx @@ -1,23 +1,26 @@ -import { ComponentProps } from 'react'; -import { ShallowWrapper, shallow } from 'enzyme'; +import { render, screen, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; -import QuickStartConclusion from '../QuickStartConclusion'; import QuickStartContent from '../QuickStartContent'; -import QuickStartIntroduction from '../QuickStartIntroduction'; -import QuickStartTasks from '../QuickStartTasks'; -type QuickStartContentProps = ComponentProps; +const contextValues = { + ...QuickStartContextDefaults, + getResource: (key: string) => key, +}; -let wrapper: ShallowWrapper; +const quickStart = getQuickStartByName('explore-serverless', allQuickStarts); +const totalTasks = quickStart.spec.tasks.length; -const props: QuickStartContentProps = { - quickStart: getQuickStartByName('explore-serverless', allQuickStarts), +const defaultProps = { + quickStart, allTaskStatuses: [ QuickStartTaskStatus.INIT, QuickStartTaskStatus.INIT, - QuickStartTaskStatus.INIT, ], taskNumber: -1, onTaskReview: jest.fn(), @@ -25,28 +28,50 @@ const props: QuickStartContentProps = { onQuickStartChange: jest.fn(), }; +const renderWithContext = (props = {}) => + render( + + + , + ); + describe('QuickStartContent', () => { beforeEach(() => { - wrapper = shallow(); + jest.clearAllMocks(); }); - it('should render QuickStartIntroduction when the tour status is Not Started', () => { - expect(wrapper.find(QuickStartIntroduction).length).toBe(1); - expect(wrapper.find(QuickStartTasks).length).toBe(0); - expect(wrapper.find(QuickStartConclusion).length).toBe(0); + it('should render QuickStartIntroduction when the tour status is Not Started', async () => { + renderWithContext(); + await waitFor(() => { + expect(document.body.textContent).toMatch( + new RegExp(`In this quick start, you will complete ${totalTasks} task`), + ); + }); + expect(document.body.textContent).not.toMatch(/Your Serverless Operator is ready/); }); - it('should render QuickStartTasks when the tour is In Progress', () => { - wrapper = shallow(); - expect(wrapper.find(QuickStartIntroduction).length).toBe(0); - expect(wrapper.find(QuickStartTasks).length).toBe(1); - expect(wrapper.find(QuickStartConclusion).length).toBe(0); + it('should render QuickStartTasks when the tour is In Progress', async () => { + // taskNumber is 0-based index into spec.tasks; first task visible and active when non-INIT + renderWithContext({ + taskNumber: 0, + allTaskStatuses: [QuickStartTaskStatus.VISITED, QuickStartTaskStatus.INIT], + }); + await waitFor(() => { + expect(document.body.textContent).toMatch(/Install the OpenShift Serverless Operator/); + }); + expect(document.body.textContent).not.toMatch( + new RegExp(`In this quick start, you will complete ${totalTasks} task`), + ); }); - it('should render QuickStartConclusion when the tour is Complete', () => { - wrapper = shallow(); - expect(wrapper.find(QuickStartIntroduction).length).toBe(0); - expect(wrapper.find(QuickStartTasks).length).toBe(0); - expect(wrapper.find(QuickStartConclusion).length).toBe(1); + it('should render QuickStartConclusion when the tour is Complete', async () => { + renderWithContext({ taskNumber: totalTasks }); + await waitFor(() => { + expect(document.body.textContent).toMatch(/Your Serverless Operator is ready/); + }); + // Conclusion still lists task headers; intro copy is not shown + expect(document.body.textContent).not.toMatch( + /In this quick start, you will complete \d+ task/, + ); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx index 80b938d1..3736e6b4 100644 --- a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx @@ -1,103 +1,82 @@ -import * as React from 'react'; -import { Button } from '@patternfly/react-core'; -import { shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { QuickStartStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import QuickStartFooter from '../QuickStartFooter'; -jest.mock('react', () => { - const ActualReact = require.requireActual('react'); - return { - ...ActualReact, - useContext: () => jest.fn(), - }; -}); +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + startQuickStart: jest.fn(), + restartQuickStart: jest.fn(), + getResource: (key: string) => key, +}; -describe('QuickStartFooter', () => { - type QuickStartFooterProps = React.ComponentProps; - let quickStartFooterProps: QuickStartFooterProps; - beforeEach(() => { - spyOn(React, 'useContext').and.returnValue({ - activeQuickStartID: '', - startQuickStart: () => {}, - restartQuickStart: () => {}, - getResource: (key) => `quickstart~${key}`, - }); - }); +const renderWithContext = (props: any) => + render( + + + , + ); +describe('QuickStartFooter', () => { it('should load Start button for not started tours', () => { - quickStartFooterProps = { + renderWithContext({ status: QuickStartStatus.NOT_STARTED, footerClass: 'test', quickStartId: 'test-quickstart', - onNext: () => null, - onBack: () => null, + onNext: jest.fn(), + onBack: jest.fn(), totalTasks: 4, taskNumber: -1, - }; - - const quickStartFooterWrapper = shallow(); - const footerButtons = quickStartFooterWrapper.find(Button); - expect(footerButtons.exists()).toBeTruthy(); - expect(footerButtons.length).toEqual(1); - expect(footerButtons.at(0).childAt(0).text()).toBe('quickstart~Start'); + }); + expect(screen.getByRole('button', { name: 'Start' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Back' })).not.toBeInTheDocument(); }); - it('should load Continue and Restart buttons for in progress tours at into page', () => { - quickStartFooterProps = { + it('should load Continue and Restart buttons for in progress tours at intro page', () => { + renderWithContext({ status: QuickStartStatus.IN_PROGRESS, footerClass: 'test', quickStartId: 'test-quickstart', - onNext: () => null, - onBack: () => null, + onNext: jest.fn(), + onBack: jest.fn(), totalTasks: 4, taskNumber: -1, - }; - - const quickStartFooterWrapper = shallow(); - const footerButtons = quickStartFooterWrapper.find(Button); - expect(footerButtons.exists()).toBeTruthy(); - expect(footerButtons.length).toEqual(2); - expect(footerButtons.at(0).childAt(0).text()).toBe('quickstart~Continue'); - expect(footerButtons.at(1).childAt(0).text()).toBe('quickstart~Restart'); + }); + expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); - it('should load Next and Back buttons, and Restart link for in progress tours in task page', () => { - quickStartFooterProps = { + it('should load Next, Back, and Restart buttons for in progress tours in task page', () => { + renderWithContext({ status: QuickStartStatus.IN_PROGRESS, footerClass: 'test', quickStartId: 'test-quickstart', - onNext: () => null, - onBack: () => null, + onNext: jest.fn(), + onBack: jest.fn(), totalTasks: 4, taskNumber: 2, - }; - - const quickStartFooterWrapper = shallow(); - const footerButtons = quickStartFooterWrapper.find(Button); - expect(footerButtons.exists()).toBeTruthy(); - expect(footerButtons.length).toEqual(3); - expect(footerButtons.at(0).childAt(0).text()).toBe('quickstart~Next'); - expect(footerButtons.at(1).childAt(0).text()).toBe('quickstart~Back'); - expect(footerButtons.at(2).childAt(0).text()).toBe('quickstart~Restart'); + }); + expect(screen.getByRole('button', { name: 'Next' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); it('should load Close, Back and Restart buttons for completed tours in conclusion page', () => { - quickStartFooterProps = { + renderWithContext({ status: QuickStartStatus.COMPLETE, footerClass: 'test', quickStartId: 'test-quickstart', - onNext: () => null, - onBack: () => null, + onNext: jest.fn(), + onBack: jest.fn(), totalTasks: 4, taskNumber: 4, - }; - - const quickStartFooterWrapper = shallow(); - const footerButtons = quickStartFooterWrapper.find(Button); - expect(footerButtons.exists()).toBeTruthy(); - expect(footerButtons.length).toEqual(3); - expect(footerButtons.at(0).childAt(0).text()).toBe('quickstart~Close'); - expect(footerButtons.at(1).childAt(0).text()).toBe('quickstart~Back'); - expect(footerButtons.at(2).childAt(0).text()).toBe('quickstart~Restart'); + }); + expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx index e344d612..cc836d29 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx @@ -1,43 +1,44 @@ -import { ComponentProps } from 'react'; -import { Title, WizardNavItem } from '@patternfly/react-core'; -import { ShallowWrapper, shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import QuickStartTaskHeader from '../QuickStartTaskHeader'; -type QuickStartTaskHeaderProps = ComponentProps; -let wrapper: ShallowWrapper; -const props: QuickStartTaskHeaderProps = { +const contextValues = { + ...QuickStartContextDefaults, + getResource: (key: string) => key, +}; + +const defaultProps = { title: 'title', taskIndex: 1, subtitle: 'subtitle', taskStatus: QuickStartTaskStatus.INIT, - size: 'lg', + size: 'lg' as const, isActiveTask: true, onTaskSelect: jest.fn(), }; -describe('QuickStartTaskHeader', () => { - beforeEach(() => { - // DOMPurify.addHook = jest.fn(); - wrapper = shallow(); - }); +const renderWithContext = (props = {}) => + render( + + + , + ); +describe('QuickStartTaskHeader', () => { it('should render subtitle for active task', () => { - expect(wrapper.find(WizardNavItem).dive().find(Title).length).toBe(1); + renderWithContext(); expect( - wrapper.find(WizardNavItem).dive().find('[data-test-id="quick-start-task-subtitle"]').props() - .children, - ).toEqual(props.subtitle); + screen.getByRole('button', { name: new RegExp(`${defaultProps.title}.*${defaultProps.subtitle}`) }), + ).toBeInTheDocument(); }); + it('should not render subtitle if task is not active', () => { - wrapper = shallow(); - expect(wrapper.find(WizardNavItem).dive().find(Title).length).toBe(1); - expect( - wrapper - .find(WizardNavItem) - .dive() - .find('[data-test-id="quick-start-task-subtitle"]') - .exists(), - ).toBe(false); + renderWithContext({ isActiveTask: false }); + expect(screen.getByRole('button', { name: defaultProps.title })).toBeInTheDocument(); + expect(screen.queryByText(defaultProps.subtitle)).not.toBeInTheDocument(); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx index 48c91328..5386524a 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx @@ -1,42 +1,54 @@ -import { Alert } from '@patternfly/react-core'; -import { ShallowWrapper, shallow } from 'enzyme'; +import { render, screen, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; -import QuickStartMarkdownView from '../../QuickStartMarkdownView'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartTaskReview from '../QuickStartTaskReview'; -import { ComponentProps } from 'react'; -type QuickStartTaskReviewProps = ComponentProps; -let wrapper: ShallowWrapper; -const props: QuickStartTaskReviewProps = { - review: getQuickStartByName('explore-serverless', allQuickStarts).spec.tasks[0].review, +const contextValues = { + ...QuickStartContextDefaults, + getResource: (key: string) => key, +}; + +const review = getQuickStartByName('explore-serverless', allQuickStarts).spec.tasks[0].review; + +const defaultProps = { + review, taskStatus: QuickStartTaskStatus.REVIEW, onTaskReview: jest.fn(), }; -describe('QuickStartTaskReview', () => { - it('should render alert with info variant when task status is review', () => { - wrapper = shallow(); - expect(wrapper.find(Alert).props().variant).toBe('info'); - }); +const renderWithContext = (props = {}) => + render( + + + , + ); - it('should render alert with success variant when task status is success', () => { - props.taskStatus = QuickStartTaskStatus.SUCCESS; - wrapper = shallow(); - expect(wrapper.find(Alert).props().variant).toBe('success'); +describe('QuickStartTaskReview', () => { + it('should render review prompt with yes/no while task is in review', () => { + renderWithContext(); + expect(screen.getByRole('alert')).toBeInTheDocument(); + expect(screen.getByText('Check your work')).toBeInTheDocument(); + expect(screen.getByRole('radio', { name: 'Yes' })).not.toBeChecked(); + expect(screen.getByRole('radio', { name: 'No' })).not.toBeChecked(); }); - it('should render alert with danger variant when task status is failed', () => { - props.taskStatus = QuickStartTaskStatus.FAILED; - wrapper = shallow(); - expect(wrapper.find(Alert).props().variant).toBe('danger'); + it('should mark Yes selected when task status is success', () => { + renderWithContext({ taskStatus: QuickStartTaskStatus.SUCCESS }); + expect(screen.getByRole('radio', { name: 'Yes' })).toBeChecked(); + expect(screen.getByRole('radio', { name: 'No' })).not.toBeChecked(); }); - it('should render task help in markdown when task status is failed', () => { - wrapper = shallow(); - expect(wrapper.find(QuickStartMarkdownView).at(1).props().content).toEqual( - props.review.failedTaskHelp, - ); + it('should mark No selected and show failed-task help when task status is failed', async () => { + renderWithContext({ taskStatus: QuickStartTaskStatus.FAILED }); + expect(screen.getByRole('radio', { name: 'No' })).toBeChecked(); + expect(screen.getByRole('radio', { name: 'Yes' })).not.toBeChecked(); + await waitFor(() => { + expect(document.body.textContent).toMatch(/This task is incomplete/); + }); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx index cc8f6b21..f3b91a09 100644 --- a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx @@ -1,25 +1,25 @@ -import * as React from 'react'; -import { ShallowWrapper, shallow } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; -import QuickStartMarkdownView from '../../QuickStartMarkdownView'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; +import { + QuickStartContext, + QuickStartContextDefaults, +} from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; -import TaskHeader from '../QuickStartTaskHeader'; -import QuickStartTaskReview from '../QuickStartTaskReview'; -import QuickStartTask from '../QuickStartTasks'; +import QuickStartTasks from '../QuickStartTasks'; -jest.mock('react', () => { - const ActualReact = require.requireActual('react'); - return { - ...ActualReact, - useContext: () => jest.fn(), - }; -}); +const contextValues = { + ...QuickStartContextDefaults, + activeQuickStartID: '', + startQuickStart: jest.fn(), + restartQuickStart: jest.fn(), + getResource: (key: string) => key, +}; -type QuickStartTaskProps = React.ComponentProps; -let wrapper: ShallowWrapper; -const props: QuickStartTaskProps = { - tasks: getQuickStartByName('monitor-sampleapp', allQuickStarts).spec.tasks, +const tasks = getQuickStartByName('monitor-sampleapp', allQuickStarts).spec.tasks; + +const defaultProps = { + tasks, allTaskStatuses: [ QuickStartTaskStatus.SUCCESS, QuickStartTaskStatus.INIT, @@ -30,49 +30,48 @@ const props: QuickStartTaskProps = { onTaskSelect: jest.fn(), }; +const renderWithContext = (props = {}) => + render( + + + , + ); + describe('QuickStartTasks', () => { beforeEach(() => { - spyOn(React, 'useContext').and.returnValue({ - activeQuickStartID: '', - startQuickStart: () => {}, - restartQuickStart: () => {}, - getResource: (key) => `quickstart~${key}`, - }); - wrapper = shallow(); + jest.clearAllMocks(); }); it('should render correct number of tasks based on currentTaskIndex', () => { - expect(wrapper.find(TaskHeader).length).toBe(1); + renderWithContext(); + // Only non-INIT tasks are rendered; first task is SUCCESS so it shows + const taskHeaders = screen.getAllByRole('listitem'); + expect(taskHeaders).toHaveLength(1); }); - it('should render SyncMarkdownView with description if a task is active', () => { - wrapper = shallow( - , - ); - expect(wrapper.find(QuickStartMarkdownView).at(0).props().content).toEqual( - props.tasks[2].description, - ); + it('should render description if a task is active', () => { + renderWithContext({ + allTaskStatuses: [ + QuickStartTaskStatus.SUCCESS, + QuickStartTaskStatus.FAILED, + QuickStartTaskStatus.VISITED, + ], + taskNumber: 2, + }); + // All 3 tasks are non-INIT, so all render + const taskHeaders = screen.getAllByRole('listitem'); + expect(taskHeaders).toHaveLength(3); }); it('should render review when task is active and in Review state', () => { - wrapper = shallow( - , - ); - expect(wrapper.find(QuickStartTaskReview).exists()).toBe(true); + renderWithContext({ + allTaskStatuses: [ + QuickStartTaskStatus.SUCCESS, + QuickStartTaskStatus.REVIEW, + QuickStartTaskStatus.INIT, + ], + }); + // "Check your work" is the alert title for QuickStartTaskReview + expect(screen.getByText('Check your work')).toBeInTheDocument(); }); }); diff --git a/test-setup.js b/test-setup.js index 82edfc9e..41b3e374 100644 --- a/test-setup.js +++ b/test-setup.js @@ -1,4 +1,2 @@ -import { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -configure({ adapter: new Adapter() }); +// This file is intentionally left minimal. +// enzyme setup has been removed in favor of @testing-library/react. diff --git a/yarn.lock b/yarn.lock index b90f479d..39e1bf6a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,13 @@ __metadata: version: 8 cacheKey: 10c0 +"@adobe/css-tools@npm:^4.4.0": + version: 4.4.4 + resolution: "@adobe/css-tools@npm:4.4.4" + checksum: 10c0/8f3e6cfaa5e6286e6f05de01d91d060425be2ebaef490881f5fe6da8bbdb336835c5d373ea337b0c3b0a1af4be048ba18780f0f6021d30809b4545922a7e13d9 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.2.0": version: 2.3.0 resolution: "@ampproject/remapping@npm:2.3.0" @@ -2596,6 +2603,7 @@ __metadata: "@rollup/plugin-commonjs": "npm:^17.0.0" "@rollup/plugin-json": "npm:^4.1.0" "@rollup/plugin-node-resolve": "npm:^11.1.0" + "@testing-library/jest-dom": "npm:^6.9.1" "@testing-library/react": "npm:^13.4.0" "@types/dompurify": "npm:^3.0.5" "@types/enzyme": "npm:^3.10.7" @@ -2901,6 +2909,20 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:^6.9.1": + version: 6.9.1 + resolution: "@testing-library/jest-dom@npm:6.9.1" + dependencies: + "@adobe/css-tools": "npm:^4.4.0" + aria-query: "npm:^5.0.0" + css.escape: "npm:^1.5.1" + dom-accessibility-api: "npm:^0.6.3" + picocolors: "npm:^1.1.1" + redent: "npm:^3.0.0" + checksum: 10c0/4291ebd2f0f38d14cefac142c56c337941775a5807e2a3d6f1a14c2fbd6be76a18e498ed189e95bedc97d9e8cf1738049bc76c85b5bc5e23fae7c9e10f7b3a12 + languageName: node + linkType: hard + "@testing-library/react@npm:^13.4.0": version: 13.4.0 resolution: "@testing-library/react@npm:13.4.0" @@ -4548,6 +4570,13 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:^5.0.0": + version: 5.3.2 + resolution: "aria-query@npm:5.3.2" + checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e + languageName: node + linkType: hard + "arr-diff@npm:^2.0.0": version: 2.0.0 resolution: "arr-diff@npm:2.0.0" @@ -7422,6 +7451,13 @@ __metadata: languageName: node linkType: hard +"css.escape@npm:^1.5.1": + version: 1.5.1 + resolution: "css.escape@npm:1.5.1" + checksum: 10c0/5e09035e5bf6c2c422b40c6df2eb1529657a17df37fda5d0433d722609527ab98090baf25b13970ca754079a0f3161dd3dfc0e743563ded8cfa0749d861c1525 + languageName: node + linkType: hard + "cssesc@npm:^3.0.0": version: 3.0.0 resolution: "cssesc@npm:3.0.0" @@ -8137,6 +8173,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.6.3": + version: 0.6.3 + resolution: "dom-accessibility-api@npm:0.6.3" + checksum: 10c0/10bee5aa514b2a9a37c87cd81268db607a2e933a050074abc2f6fa3da9080ebed206a320cbc123567f2c3087d22292853bdfdceaffdd4334ffe2af9510b29360 + languageName: node + linkType: hard + "dom-converter@npm:^0.2.0": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" @@ -18295,6 +18338,16 @@ __metadata: languageName: node linkType: hard +"redent@npm:^3.0.0": + version: 3.0.0 + resolution: "redent@npm:3.0.0" + dependencies: + indent-string: "npm:^4.0.0" + strip-indent: "npm:^3.0.0" + checksum: 10c0/d64a6b5c0b50eb3ddce3ab770f866658a2b9998c678f797919ceb1b586bab9259b311407280bd80b804e2a7c7539b19238ae6a2a20c843f1a7fcff21d48c2eae + languageName: node + linkType: hard + "reduce-flatten@npm:^1.0.1": version: 1.0.1 resolution: "reduce-flatten@npm:1.0.1" From b14778281f6673af63dc54311b789c2d07090e3a Mon Sep 17 00:00:00 2001 From: nicolethoen Date: Mon, 30 Mar 2026 16:46:32 -0400 Subject: [PATCH 2/3] fix linting issues --- .../catalog/__tests__/QuickStartCatalog.spec.tsx | 9 ++------- .../src/catalog/__tests__/QuickStartTile.spec.tsx | 13 +++---------- .../__tests__/QuickStartTileDescription.spec.tsx | 9 ++------- .../__tests__/QuickStartConclusion.spec.tsx | 9 ++++----- .../controller/__tests__/QuickStartContent.spec.tsx | 12 +++--------- .../controller/__tests__/QuickStartFooter.spec.tsx | 5 +---- .../__tests__/QuickStartTaskHeader.spec.tsx | 9 ++++----- .../__tests__/QuickStartTaskReview.spec.tsx | 5 +---- .../controller/__tests__/QuickStartTasks.spec.tsx | 5 +---- 9 files changed, 21 insertions(+), 55 deletions(-) diff --git a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx index adee908a..fb3f0102 100644 --- a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx @@ -1,9 +1,6 @@ import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartCatalog from '../QuickStartCatalog'; const contextValues = { @@ -32,9 +29,7 @@ describe('QuickStartCatalog', () => { renderWithContext({ quickStarts }); // Each tile exposes the quick start display name as the title control (link-styled button) quickStarts.forEach((qs) => { - expect( - screen.getByRole('button', { name: qs.spec.displayName }), - ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: qs.spec.displayName })).toBeInTheDocument(); }); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx index 793fecbd..68a70733 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx @@ -1,10 +1,7 @@ import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; import { QuickStartStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartTile from '../QuickStartTile'; const contextValues = { @@ -32,9 +29,7 @@ describe('QuickStartTile', () => { onClick: jest.fn(), isActive: false, }); - expect( - screen.getByRole('button', { name: quickStart.spec.displayName }), - ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: quickStart.spec.displayName })).toBeInTheDocument(); // Status label is omitted for not-started tiles expect(screen.queryByText('In progress')).not.toBeInTheDocument(); }); @@ -47,9 +42,7 @@ describe('QuickStartTile', () => { onClick: jest.fn(), isActive: true, }); - expect( - screen.getByRole('button', { name: quickStart.spec.displayName }), - ).toBeInTheDocument(); + expect(screen.getByRole('button', { name: quickStart.spec.displayName })).toBeInTheDocument(); expect(screen.getByText('In progress')).toBeInTheDocument(); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx index cdd02bf9..30d9e6e2 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx @@ -1,9 +1,6 @@ import { render, screen } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartTileDescription from '../QuickStartTileDescription'; const contextValues = { @@ -25,9 +22,7 @@ describe('QuickStartTileDescription', () => { it('should show prerequisites only if provided', () => { const quickStart = getQuickStarts()[0].spec; renderWithContext({ description: quickStart.description }); - expect( - screen.queryByRole('button', { name: 'Show prerequisites' }), - ).not.toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Show prerequisites' })).not.toBeInTheDocument(); }); it('should render prerequisites trigger when prerequisite list is non-empty', () => { diff --git a/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx b/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx index 3034c839..85746c68 100644 --- a/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartConclusion.spec.tsx @@ -1,10 +1,7 @@ import { render, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartConclusion from '../QuickStartConclusion'; @@ -52,7 +49,9 @@ describe('QuickStartConclusion', () => { nextQuickStarts: [getQuickStartByName('explore-pipelines', allQuickStarts)], }); await waitFor(() => { - expect(document.body.textContent).toMatch(/Start Installing the Pipelines Operator quick start/); + expect(document.body.textContent).toMatch( + /Start Installing the Pipelines Operator quick start/, + ); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx b/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx index 8eef851a..e433caa2 100644 --- a/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartContent.spec.tsx @@ -1,10 +1,7 @@ -import { render, screen, waitFor } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartContent from '../QuickStartContent'; @@ -18,10 +15,7 @@ const totalTasks = quickStart.spec.tasks.length; const defaultProps = { quickStart, - allTaskStatuses: [ - QuickStartTaskStatus.INIT, - QuickStartTaskStatus.INIT, - ], + allTaskStatuses: [QuickStartTaskStatus.INIT, QuickStartTaskStatus.INIT], taskNumber: -1, onTaskReview: jest.fn(), onTaskSelect: jest.fn(), diff --git a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx index 3736e6b4..862feba1 100644 --- a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx @@ -1,9 +1,6 @@ import { render, screen } from '@testing-library/react'; import { QuickStartStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartFooter from '../QuickStartFooter'; const contextValues = { diff --git a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx index cc836d29..fb000218 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx @@ -1,9 +1,6 @@ import { render, screen } from '@testing-library/react'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartTaskHeader from '../QuickStartTaskHeader'; const contextValues = { @@ -32,7 +29,9 @@ describe('QuickStartTaskHeader', () => { it('should render subtitle for active task', () => { renderWithContext(); expect( - screen.getByRole('button', { name: new RegExp(`${defaultProps.title}.*${defaultProps.subtitle}`) }), + screen.getByRole('button', { + name: new RegExp(`${defaultProps.title}.*${defaultProps.subtitle}`), + }), ).toBeInTheDocument(); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx index 5386524a..1fb2087e 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx @@ -1,10 +1,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartTaskReview from '../QuickStartTaskReview'; diff --git a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx index f3b91a09..31baff83 100644 --- a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx @@ -1,10 +1,7 @@ import { render, screen } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; -import { - QuickStartContext, - QuickStartContextDefaults, -} from '../../utils/quick-start-context'; +import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import { getQuickStartByName } from '../../utils/quick-start-utils'; import QuickStartTasks from '../QuickStartTasks'; From f162214e7a39b3bcd010e4f7c30488980cfcc620 Mon Sep 17 00:00:00 2001 From: nicolethoen Date: Mon, 30 Mar 2026 17:03:36 -0400 Subject: [PATCH 3/3] remove enzyme & address test warnings --- before-tests.js | 31 ++ packages/module/package.json | 5 - .../__tests__/QuickStartCatalog.spec.tsx | 12 +- .../catalog/__tests__/QuickStartTile.spec.tsx | 18 +- .../QuickStartTileDescription.spec.tsx | 18 +- .../__tests__/QuickStartFooter.spec.tsx | 26 +- .../__tests__/QuickStartTaskHeader.spec.tsx | 22 +- .../__tests__/QuickStartTaskReview.spec.tsx | 16 +- .../__tests__/QuickStartTasks.spec.tsx | 30 +- yarn.lock | 274 ++---------------- 10 files changed, 142 insertions(+), 310 deletions(-) diff --git a/before-tests.js b/before-tests.js index 5c3f6e20..99bb8288 100644 --- a/before-tests.js +++ b/before-tests.js @@ -1,3 +1,34 @@ /* eslint-env node */ import 'url-search-params-polyfill'; + +// Suppress act() warnings only for async markdown rendering (SyncMarkdownView / +// QuickStartMarkdownView). Other act warnings still surface so new tests stay honest. +const originalError = console.error; + +const isMarkdownActWarning = (...args) => { + const message = args + .map((a) => { + if (typeof a === 'string') { + return a; + } + if (a instanceof Error && typeof a.message === 'string') { + return a.message; + } + return ''; + }) + .join('\n'); + if (!message.includes('was not wrapped in act(')) { + return false; + } + return ( + message.includes('SyncMarkdownView') || message.includes('QuickStartMarkdownView') + ); +}; + +console.error = (...args) => { + if (isMarkdownActWarning(...args)) { + return; + } + originalError.call(console, ...args); +}; diff --git a/packages/module/package.json b/packages/module/package.json index 1687b087..f3803074 100644 --- a/packages/module/package.json +++ b/packages/module/package.json @@ -69,8 +69,6 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^13.4.0", "@types/dompurify": "^3.0.5", - "@types/enzyme": "^3.10.7", - "@types/enzyme-adapter-react-16": "^1.0.6", "@types/history": "^4.7.8", "@types/node": "^14.14.35", "@types/react": "^18.2.79", @@ -78,9 +76,6 @@ "clean-css-cli": "^4.3.0", "concat-files": "^0.1.1", "dart-sass": "^1.25.0", - "enzyme": "^3.7.0", - "enzyme-adapter-react-16": "^1.15.5", - "enzyme-to-json": "^3.6.1", "monaco-editor": "0.34.1", "node-sass-glob-importer": "^5.3.2", "prettier": "^2.8.8", diff --git a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx index fb3f0102..1a7f4006 100644 --- a/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartCatalog.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartCatalog from '../QuickStartCatalog'; @@ -24,12 +24,16 @@ describe('QuickStartCatalog', () => { expect(screen.queryByRole('article')).not.toBeInTheDocument(); }); - it('should load a gallery if QS exist', () => { + it('should load a gallery if QS exist', async () => { const quickStarts = getQuickStarts(); renderWithContext({ quickStarts }); // Each tile exposes the quick start display name as the title control (link-styled button) - quickStarts.forEach((qs) => { - expect(screen.getByRole('button', { name: qs.spec.displayName })).toBeInTheDocument(); + await waitFor(() => { + quickStarts.forEach((qs) => { + expect( + screen.getByRole('button', { name: qs.spec.displayName }), + ).toBeInTheDocument(); + }); }); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx index 68a70733..02059579 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTile.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; import { QuickStartStatus } from '../../utils/quick-start-types'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; @@ -21,7 +21,7 @@ const renderWithContext = (props: any) => ); describe('QuickStartTile', () => { - it('should load proper catalog tile without featured property', () => { + it('should load proper catalog tile without featured property', async () => { const quickStart = quickstarts[0]; renderWithContext({ quickStart, @@ -29,12 +29,16 @@ describe('QuickStartTile', () => { onClick: jest.fn(), isActive: false, }); - expect(screen.getByRole('button', { name: quickStart.spec.displayName })).toBeInTheDocument(); + await waitFor(() => { + expect( + screen.getByRole('button', { name: quickStart.spec.displayName }), + ).toBeInTheDocument(); + }); // Status label is omitted for not-started tiles expect(screen.queryByText('In progress')).not.toBeInTheDocument(); }); - it('should load proper catalog tile with featured property', () => { + it('should load proper catalog tile with featured property', async () => { const quickStart = quickstarts[1]; renderWithContext({ quickStart, @@ -42,7 +46,11 @@ describe('QuickStartTile', () => { onClick: jest.fn(), isActive: true, }); - expect(screen.getByRole('button', { name: quickStart.spec.displayName })).toBeInTheDocument(); + await waitFor(() => { + expect( + screen.getByRole('button', { name: quickStart.spec.displayName }), + ).toBeInTheDocument(); + }); expect(screen.getByText('In progress')).toBeInTheDocument(); }); }); diff --git a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx index 30d9e6e2..67cb1f73 100644 --- a/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx +++ b/packages/module/src/catalog/__tests__/QuickStartTileDescription.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { getQuickStarts } from '../../data/test-utils'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartTileDescription from '../QuickStartTileDescription'; @@ -19,18 +19,26 @@ const renderWithContext = (props: any) => ); describe('QuickStartTileDescription', () => { - it('should show prerequisites only if provided', () => { + it('should show prerequisites only if provided', async () => { const quickStart = getQuickStarts()[0].spec; renderWithContext({ description: quickStart.description }); - expect(screen.queryByRole('button', { name: 'Show prerequisites' })).not.toBeInTheDocument(); + await waitFor(() => { + expect( + screen.queryByRole('button', { name: 'Show prerequisites' }), + ).not.toBeInTheDocument(); + }); }); - it('should render prerequisites trigger when prerequisite list is non-empty', () => { + it('should render prerequisites trigger when prerequisite list is non-empty', async () => { const quickStart = getQuickStarts()[2].spec; renderWithContext({ description: quickStart.description, prerequisites: quickStart.prerequisites, }); - expect(screen.getByRole('button', { name: 'Show prerequisites' })).toBeInTheDocument(); + await waitFor(() => { + expect( + screen.getByRole('button', { name: 'Show prerequisites' }), + ).toBeInTheDocument(); + }); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx index 862feba1..855b1114 100644 --- a/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartFooter.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { QuickStartStatus } from '../../utils/quick-start-types'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartFooter from '../QuickStartFooter'; @@ -19,7 +19,7 @@ const renderWithContext = (props: any) => ); describe('QuickStartFooter', () => { - it('should load Start button for not started tours', () => { + it('should load Start button for not started tours', async () => { renderWithContext({ status: QuickStartStatus.NOT_STARTED, footerClass: 'test', @@ -29,11 +29,13 @@ describe('QuickStartFooter', () => { totalTasks: 4, taskNumber: -1, }); - expect(screen.getByRole('button', { name: 'Start' })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('button', { name: 'Start' })).toBeInTheDocument(); + }); expect(screen.queryByRole('button', { name: 'Back' })).not.toBeInTheDocument(); }); - it('should load Continue and Restart buttons for in progress tours at intro page', () => { + it('should load Continue and Restart buttons for in progress tours at intro page', async () => { renderWithContext({ status: QuickStartStatus.IN_PROGRESS, footerClass: 'test', @@ -43,11 +45,13 @@ describe('QuickStartFooter', () => { totalTasks: 4, taskNumber: -1, }); - expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('button', { name: 'Continue' })).toBeInTheDocument(); + }); expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); - it('should load Next, Back, and Restart buttons for in progress tours in task page', () => { + it('should load Next, Back, and Restart buttons for in progress tours in task page', async () => { renderWithContext({ status: QuickStartStatus.IN_PROGRESS, footerClass: 'test', @@ -57,12 +61,14 @@ describe('QuickStartFooter', () => { totalTasks: 4, taskNumber: 2, }); - expect(screen.getByRole('button', { name: 'Next' })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('button', { name: 'Next' })).toBeInTheDocument(); + }); expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); - it('should load Close, Back and Restart buttons for completed tours in conclusion page', () => { + it('should load Close, Back and Restart buttons for completed tours in conclusion page', async () => { renderWithContext({ status: QuickStartStatus.COMPLETE, footerClass: 'test', @@ -72,7 +78,9 @@ describe('QuickStartFooter', () => { totalTasks: 4, taskNumber: 4, }); - expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument(); + }); expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Restart' })).toBeInTheDocument(); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx index fb000218..d28a21cd 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskHeader.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; import QuickStartTaskHeader from '../QuickStartTaskHeader'; @@ -26,18 +26,22 @@ const renderWithContext = (props = {}) => ); describe('QuickStartTaskHeader', () => { - it('should render subtitle for active task', () => { + it('should render subtitle for active task', async () => { renderWithContext(); - expect( - screen.getByRole('button', { - name: new RegExp(`${defaultProps.title}.*${defaultProps.subtitle}`), - }), - ).toBeInTheDocument(); + await waitFor(() => { + expect( + screen.getByRole('button', { + name: new RegExp(`${defaultProps.title}.*${defaultProps.subtitle}`), + }), + ).toBeInTheDocument(); + }); }); - it('should not render subtitle if task is not active', () => { + it('should not render subtitle if task is not active', async () => { renderWithContext({ isActiveTask: false }); - expect(screen.getByRole('button', { name: defaultProps.title })).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('button', { name: defaultProps.title })).toBeInTheDocument(); + }); expect(screen.queryByText(defaultProps.subtitle)).not.toBeInTheDocument(); }); }); diff --git a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx index 1fb2087e..125c9ba5 100644 --- a/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTaskReview.spec.tsx @@ -26,23 +26,29 @@ const renderWithContext = (props = {}) => ); describe('QuickStartTaskReview', () => { - it('should render review prompt with yes/no while task is in review', () => { + it('should render review prompt with yes/no while task is in review', async () => { renderWithContext(); - expect(screen.getByRole('alert')).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByRole('alert')).toBeInTheDocument(); + }); expect(screen.getByText('Check your work')).toBeInTheDocument(); expect(screen.getByRole('radio', { name: 'Yes' })).not.toBeChecked(); expect(screen.getByRole('radio', { name: 'No' })).not.toBeChecked(); }); - it('should mark Yes selected when task status is success', () => { + it('should mark Yes selected when task status is success', async () => { renderWithContext({ taskStatus: QuickStartTaskStatus.SUCCESS }); - expect(screen.getByRole('radio', { name: 'Yes' })).toBeChecked(); + await waitFor(() => { + expect(screen.getByRole('radio', { name: 'Yes' })).toBeChecked(); + }); expect(screen.getByRole('radio', { name: 'No' })).not.toBeChecked(); }); it('should mark No selected and show failed-task help when task status is failed', async () => { renderWithContext({ taskStatus: QuickStartTaskStatus.FAILED }); - expect(screen.getByRole('radio', { name: 'No' })).toBeChecked(); + await waitFor(() => { + expect(screen.getByRole('radio', { name: 'No' })).toBeChecked(); + }); expect(screen.getByRole('radio', { name: 'Yes' })).not.toBeChecked(); await waitFor(() => { expect(document.body.textContent).toMatch(/This task is incomplete/); diff --git a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx index 31baff83..649f3a4d 100644 --- a/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx +++ b/packages/module/src/controller/__tests__/QuickStartTasks.spec.tsx @@ -1,4 +1,4 @@ -import { render, screen } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import { allQuickStarts } from '../../data/quick-start-test-data'; import { QuickStartTaskStatus } from '../../utils/quick-start-types'; import { QuickStartContext, QuickStartContextDefaults } from '../../utils/quick-start-context'; @@ -39,14 +39,16 @@ describe('QuickStartTasks', () => { jest.clearAllMocks(); }); - it('should render correct number of tasks based on currentTaskIndex', () => { + it('should render correct number of tasks based on currentTaskIndex', async () => { renderWithContext(); - // Only non-INIT tasks are rendered; first task is SUCCESS so it shows - const taskHeaders = screen.getAllByRole('listitem'); - expect(taskHeaders).toHaveLength(1); + await waitFor(() => { + // Only non-INIT tasks are rendered; first task is SUCCESS so it shows + const taskHeaders = screen.getAllByRole('listitem'); + expect(taskHeaders).toHaveLength(1); + }); }); - it('should render description if a task is active', () => { + it('should render description if a task is active', async () => { renderWithContext({ allTaskStatuses: [ QuickStartTaskStatus.SUCCESS, @@ -55,12 +57,14 @@ describe('QuickStartTasks', () => { ], taskNumber: 2, }); - // All 3 tasks are non-INIT, so all render - const taskHeaders = screen.getAllByRole('listitem'); - expect(taskHeaders).toHaveLength(3); + await waitFor(() => { + // All 3 tasks are non-INIT, so all render + const taskHeaders = screen.getAllByRole('listitem'); + expect(taskHeaders).toHaveLength(3); + }); }); - it('should render review when task is active and in Review state', () => { + it('should render review when task is active and in Review state', async () => { renderWithContext({ allTaskStatuses: [ QuickStartTaskStatus.SUCCESS, @@ -68,7 +72,9 @@ describe('QuickStartTasks', () => { QuickStartTaskStatus.INIT, ], }); - // "Check your work" is the alert title for QuickStartTaskReview - expect(screen.getByText('Check your work')).toBeInTheDocument(); + await waitFor(() => { + // "Check your work" is the alert title for QuickStartTaskReview + expect(screen.getByText('Check your work')).toBeInTheDocument(); + }); }); }); diff --git a/yarn.lock b/yarn.lock index 39e1bf6a..ac8cbdc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2606,8 +2606,6 @@ __metadata: "@testing-library/jest-dom": "npm:^6.9.1" "@testing-library/react": "npm:^13.4.0" "@types/dompurify": "npm:^3.0.5" - "@types/enzyme": "npm:^3.10.7" - "@types/enzyme-adapter-react-16": "npm:^1.0.6" "@types/history": "npm:^4.7.8" "@types/node": "npm:^14.14.35" "@types/react": "npm:^18.2.79" @@ -2616,9 +2614,6 @@ __metadata: concat-files: "npm:^0.1.1" dart-sass: "npm:^1.25.0" dompurify: "npm:^3.3.2" - enzyme: "npm:^3.7.0" - enzyme-adapter-react-16: "npm:^1.15.5" - enzyme-to-json: "npm:^3.6.1" history: "npm:^5.0.0" monaco-editor: "npm:0.34.1" node-sass-glob-importer: "npm:^5.3.2" @@ -2977,15 +2972,6 @@ __metadata: languageName: node linkType: hard -"@types/cheerio@npm:*, @types/cheerio@npm:^0.22.22": - version: 0.22.30 - resolution: "@types/cheerio@npm:0.22.30" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/b5ade8b6936a176a7dcbc8b5ca458d8c349f97ebaebc7a897df09aa3ffb7e9194c39e494feb786c1d34143dcbabbc0247b7f71bf20a5173c5366dd0a362b2436 - languageName: node - linkType: hard - "@types/connect-history-api-fallback@npm:^1.5.4": version: 1.5.4 resolution: "@types/connect-history-api-fallback@npm:1.5.4" @@ -3083,25 +3069,6 @@ __metadata: languageName: node linkType: hard -"@types/enzyme-adapter-react-16@npm:^1.0.6": - version: 1.0.6 - resolution: "@types/enzyme-adapter-react-16@npm:1.0.6" - dependencies: - "@types/enzyme": "npm:*" - checksum: 10c0/032bde12b93b0c1215213e8a87defe916cfa6d5508d8480de933c224ebc9f3346c67a6cd6494ee83b6b8c53eeef499838002156e87f4d865cd933509ec0d3a89 - languageName: node - linkType: hard - -"@types/enzyme@npm:*, @types/enzyme@npm:^3.10.7": - version: 3.10.9 - resolution: "@types/enzyme@npm:3.10.9" - dependencies: - "@types/cheerio": "npm:*" - "@types/react": "npm:*" - checksum: 10c0/29f8de84a4bcbc8e4b22913fa5ee05958f6dd53ec597096459fcc3b0fb24c7b322e3250bc81408be31c3466c2637eb7a36d973fa4e5d7548c9d0225c9bc2fcbf - languageName: node - linkType: hard - "@types/eslint-scope@npm:^3.7.7": version: 3.7.7 resolution: "@types/eslint-scope@npm:3.7.7" @@ -4706,19 +4673,6 @@ __metadata: languageName: node linkType: hard -"array.prototype.filter@npm:^1.0.0": - version: 1.0.0 - resolution: "array.prototype.filter@npm:1.0.0" - dependencies: - call-bind: "npm:^1.0.2" - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.18.0" - es-array-method-boxes-properly: "npm:^1.0.0" - is-string: "npm:^1.0.5" - checksum: 10c0/67c971f61527c47da77ad26ef2bb06a1bb71f62032598fd5566cf2adf13bf24f140eefbb1ee8d1987a4e869699b6b20387f9bc109ff245e7a491593e656cce49 - languageName: node - linkType: hard - "array.prototype.find@npm:^2.1.1": version: 2.1.1 resolution: "array.prototype.find@npm:2.1.1" @@ -4729,7 +4683,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.2.3, array.prototype.flat@npm:^1.3.1": +"array.prototype.flat@npm:^1.3.1": version: 1.3.1 resolution: "array.prototype.flat@npm:1.3.1" dependencies: @@ -6279,19 +6233,6 @@ __metadata: languageName: node linkType: hard -"cheerio-select@npm:^1.5.0": - version: 1.5.0 - resolution: "cheerio-select@npm:1.5.0" - dependencies: - css-select: "npm:^4.1.3" - css-what: "npm:^5.0.1" - domelementtype: "npm:^2.2.0" - domhandler: "npm:^4.2.0" - domutils: "npm:^2.7.0" - checksum: 10c0/851c8f9bb74823e63547ad5a39b7e301aac88950081ecf5a253e0a8c47a813f7f3428903d35c6ad78a0518b0e9c31dd0c863296f60ab4d53363612c564f863c3 - languageName: node - linkType: hard - "cheerio-select@npm:^2.1.0": version: 2.1.0 resolution: "cheerio-select@npm:2.1.0" @@ -6325,21 +6266,6 @@ __metadata: languageName: node linkType: hard -"cheerio@npm:^1.0.0-rc.3": - version: 1.0.0-rc.10 - resolution: "cheerio@npm:1.0.0-rc.10" - dependencies: - cheerio-select: "npm:^1.5.0" - dom-serializer: "npm:^1.3.2" - domhandler: "npm:^4.2.0" - htmlparser2: "npm:^6.1.0" - parse5: "npm:^6.0.1" - parse5-htmlparser2-tree-adapter: "npm:^6.0.1" - tslib: "npm:^2.2.0" - checksum: 10c0/2bb0fae8b1941949f506ddc4df75e3c2d0e5cc6c05478f918dd64a4d2c5282ec84b243890f6a809052a8eb6214641084922c07f726b5287b5dba114b10e52cb9 - languageName: node - linkType: hard - "chokidar@npm:4.0.0": version: 4.0.0 resolution: "chokidar@npm:4.0.0" @@ -7437,7 +7363,7 @@ __metadata: languageName: node linkType: hard -"css-what@npm:^5.0.0, css-what@npm:^5.0.1": +"css-what@npm:^5.0.0": version: 5.0.1 resolution: "css-what@npm:5.0.1" checksum: 10c0/a1bec4996f51e416a28efe3b003a7fd33ff0d6a91cb97be483c647df1c499e0ae6a84849c01ae87a323fc45fdb77509da773dc9a8ebab652f0a81ac47ebbf80c @@ -8132,13 +8058,6 @@ __metadata: languageName: node linkType: hard -"discontinuous-range@npm:1.0.0": - version: 1.0.0 - resolution: "discontinuous-range@npm:1.0.0" - checksum: 10c0/487b105f83c1cc528e25e65d3c4b73958ec79769b7bd0e264414702a23a7e2b282c72982b4bef4af29fcab53f47816c3f0a5c40d85a99a490f4bc35b83dc00f8 - languageName: node - linkType: hard - "dns-packet@npm:^5.2.2": version: 5.6.0 resolution: "dns-packet@npm:5.6.0" @@ -8189,7 +8108,7 @@ __metadata: languageName: node linkType: hard -"dom-serializer@npm:^1.0.1, dom-serializer@npm:^1.3.2": +"dom-serializer@npm:^1.0.1": version: 1.3.2 resolution: "dom-serializer@npm:1.3.2" dependencies: @@ -8264,7 +8183,7 @@ __metadata: languageName: node linkType: hard -"domutils@npm:^2.5.2, domutils@npm:^2.6.0, domutils@npm:^2.7.0": +"domutils@npm:^2.5.2, domutils@npm:^2.6.0": version: 2.7.0 resolution: "domutils@npm:2.7.0" dependencies: @@ -8533,7 +8452,7 @@ __metadata: languageName: node linkType: hard -"enzyme-adapter-react-16@npm:^1.15.5, enzyme-adapter-react-16@npm:^1.15.6": +"enzyme-adapter-react-16@npm:^1.15.6": version: 1.15.6 resolution: "enzyme-adapter-react-16@npm:1.15.6" dependencies: @@ -8571,7 +8490,7 @@ __metadata: languageName: node linkType: hard -"enzyme-shallow-equal@npm:^1.0.1, enzyme-shallow-equal@npm:^1.0.4": +"enzyme-shallow-equal@npm:^1.0.4": version: 1.0.4 resolution: "enzyme-shallow-equal@npm:1.0.4" dependencies: @@ -8581,49 +8500,6 @@ __metadata: languageName: node linkType: hard -"enzyme-to-json@npm:^3.6.1": - version: 3.6.2 - resolution: "enzyme-to-json@npm:3.6.2" - dependencies: - "@types/cheerio": "npm:^0.22.22" - lodash: "npm:^4.17.21" - react-is: "npm:^16.12.0" - peerDependencies: - enzyme: ^3.4.0 - checksum: 10c0/90fba5bbcfda37f456d483a46d7a077123fb65f74e59bab1e137e30c84f5b3149114efae7f9736f7ea49dd9171299645816bc5f6649b16a19d47c8bd1d6d8065 - languageName: node - linkType: hard - -"enzyme@npm:^3.7.0": - version: 3.11.0 - resolution: "enzyme@npm:3.11.0" - dependencies: - array.prototype.flat: "npm:^1.2.3" - cheerio: "npm:^1.0.0-rc.3" - enzyme-shallow-equal: "npm:^1.0.1" - function.prototype.name: "npm:^1.1.2" - has: "npm:^1.0.3" - html-element-map: "npm:^1.2.0" - is-boolean-object: "npm:^1.0.1" - is-callable: "npm:^1.1.5" - is-number-object: "npm:^1.0.4" - is-regex: "npm:^1.0.5" - is-string: "npm:^1.0.5" - is-subset: "npm:^0.1.1" - lodash.escape: "npm:^4.0.1" - lodash.isequal: "npm:^4.5.0" - object-inspect: "npm:^1.7.0" - object-is: "npm:^1.0.2" - object.assign: "npm:^4.1.0" - object.entries: "npm:^1.1.1" - object.values: "npm:^1.1.1" - raf: "npm:^3.4.1" - rst-selector-parser: "npm:^2.2.3" - string.prototype.trim: "npm:^1.2.1" - checksum: 10c0/14081671ed77924026036ed4edb1168cdac826aadd1ab2c77a5b7fdda625589dc5a4062cd0c65ec88add3ea3f7c0ebcbf3178bcf84b43335a175d8c71a016809 - languageName: node - linkType: hard - "eol@npm:^0.9.1": version: 0.9.1 resolution: "eol@npm:0.9.1" @@ -8672,7 +8548,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.4, es-abstract@npm:^1.18.0, es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": +"es-abstract@npm:^1.17.4, es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": version: 1.21.2 resolution: "es-abstract@npm:1.21.2" dependencies: @@ -8714,13 +8590,6 @@ __metadata: languageName: node linkType: hard -"es-array-method-boxes-properly@npm:^1.0.0": - version: 1.0.0 - resolution: "es-array-method-boxes-properly@npm:1.0.0" - checksum: 10c0/4b7617d3fbd460d6f051f684ceca6cf7e88e6724671d9480388d3ecdd72119ddaa46ca31f2c69c5426a82e4b3091c1e81867c71dcdc453565cd90005ff2c382d - languageName: node - linkType: hard - "es-define-property@npm:^1.0.1": version: 1.0.1 resolution: "es-define-property@npm:1.0.1" @@ -11663,16 +11532,6 @@ __metadata: languageName: node linkType: hard -"html-element-map@npm:^1.2.0": - version: 1.3.1 - resolution: "html-element-map@npm:1.3.1" - dependencies: - array.prototype.filter: "npm:^1.0.0" - call-bind: "npm:^1.0.2" - checksum: 10c0/5ae8b37546601864eb41363a05871a896df36e59714607b1386a114d45f1c6b6cd1633d6fb09e09e5ee0f1c909d6b9c1bbca831333b8eef936312f61b1b5ecb8 - languageName: node - linkType: hard - "html-encoding-sniffer@npm:^1.0.1": version: 1.0.2 resolution: "html-encoding-sniffer@npm:1.0.2" @@ -12473,7 +12332,7 @@ __metadata: languageName: node linkType: hard -"is-boolean-object@npm:^1.0.1, is-boolean-object@npm:^1.1.0": +"is-boolean-object@npm:^1.1.0": version: 1.1.1 resolution: "is-boolean-object@npm:1.1.1" dependencies: @@ -12505,7 +12364,7 @@ __metadata: languageName: node linkType: hard -"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.1.5, is-callable@npm:^1.2.7": +"is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f @@ -12967,7 +12826,7 @@ __metadata: languageName: node linkType: hard -"is-regex@npm:^1.0.5, is-regex@npm:^1.1.0, is-regex@npm:^1.1.4": +"is-regex@npm:^1.1.0, is-regex@npm:^1.1.4": version: 1.1.4 resolution: "is-regex@npm:1.1.4" dependencies: @@ -13030,13 +12889,6 @@ __metadata: languageName: node linkType: hard -"is-subset@npm:^0.1.1": - version: 0.1.1 - resolution: "is-subset@npm:0.1.1" - checksum: 10c0/d8125598ab9077a76684e18726fb915f5cea7a7358ed0c6ff723f4484d71a0a9981ee5aae06c44de99cfdef0fefce37438c6257ab129e53c82045ea0c2acdebf - languageName: node - linkType: hard - "is-symbol@npm:^1.0.2, is-symbol@npm:^1.0.3": version: 1.0.4 resolution: "is-symbol@npm:1.0.4" @@ -14612,27 +14464,6 @@ __metadata: languageName: node linkType: hard -"lodash.escape@npm:^4.0.1": - version: 4.0.1 - resolution: "lodash.escape@npm:4.0.1" - checksum: 10c0/90ade409cec05b6869090476952fdfb84d4d87b1ff4a0e03ebd590f980d9a1248d93ba14579f10d80c6429e4d6af13ba137c28db64cae6dadb71442e54a3ad2b - languageName: node - linkType: hard - -"lodash.flattendeep@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.flattendeep@npm:4.4.0" - checksum: 10c0/83cb80754b921fb4ed2c222b91a82b2524f3bdc60c3ae91e00688bd4bf1bcc28b8a2cc250e11fdc1b6da3a2de09e57008e13f15a209cafdd4f9163d047f97544 - languageName: node - linkType: hard - -"lodash.isequal@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.isequal@npm:4.5.0" - checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f - languageName: node - linkType: hard - "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -15667,13 +15498,6 @@ __metadata: languageName: node linkType: hard -"moo@npm:^0.5.0": - version: 0.5.1 - resolution: "moo@npm:0.5.1" - checksum: 10c0/2a4f2557463c3a71cf5bf06362d13ed3de065fa366e72dbc8ae1af500b7077a3d66e5c893ce24d643a81dcbf46f966f45e749ab303ccc0c56fbce3c15e941b34 - languageName: node - linkType: hard - "morgan@npm:^1.6.1": version: 1.10.0 resolution: "morgan@npm:1.10.0" @@ -15826,23 +15650,6 @@ __metadata: languageName: node linkType: hard -"nearley@npm:^2.7.10": - version: 2.20.1 - resolution: "nearley@npm:2.20.1" - dependencies: - commander: "npm:^2.19.0" - moo: "npm:^0.5.0" - railroad-diagrams: "npm:^1.0.0" - randexp: "npm:0.4.6" - bin: - nearley-railroad: bin/nearley-railroad.js - nearley-test: bin/nearley-test.js - nearley-unparse: bin/nearley-unparse.js - nearleyc: bin/nearleyc.js - checksum: 10c0/d25e1fd40b19c53a0ada6a688670f4a39063fd9553ab62885e81a82927d51572ce47193b946afa3d85efa608ba2c68f433c421f69b854bfb7f599eacb5fae37e - languageName: node - linkType: hard - "negotiator@npm:0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" @@ -16219,7 +16026,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.3, object-inspect@npm:^1.7.0, object-inspect@npm:^1.9.0": +"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": version: 1.12.3 resolution: "object-inspect@npm:1.12.3" checksum: 10c0/752bb5f4dc595e214157ea8f442adb77bdb850ace762b078d151d8b6486331ab12364997a89ee6509be1023b15adf2b3774437a7105f8a5043dfda11ed622411 @@ -16233,7 +16040,7 @@ __metadata: languageName: node linkType: hard -"object-is@npm:^1.0.2, object-is@npm:^1.1.2, object-is@npm:^1.1.5": +"object-is@npm:^1.1.2, object-is@npm:^1.1.5": version: 1.1.5 resolution: "object-is@npm:1.1.5" dependencies: @@ -16271,7 +16078,7 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.1, object.entries@npm:^1.1.2, object.entries@npm:^1.1.5, object.entries@npm:^1.1.6": +"object.entries@npm:^1.1.2, object.entries@npm:^1.1.5, object.entries@npm:^1.1.6": version: 1.1.6 resolution: "object.entries@npm:1.1.6" dependencies: @@ -16322,7 +16129,7 @@ __metadata: languageName: node linkType: hard -"object.values@npm:^1.1.1, object.values@npm:^1.1.2, object.values@npm:^1.1.6": +"object.values@npm:^1.1.2, object.values@npm:^1.1.6": version: 1.1.6 resolution: "object.values@npm:1.1.6" dependencies: @@ -16901,15 +16708,6 @@ __metadata: languageName: node linkType: hard -"parse5-htmlparser2-tree-adapter@npm:^6.0.1": - version: 6.0.1 - resolution: "parse5-htmlparser2-tree-adapter@npm:6.0.1" - dependencies: - parse5: "npm:^6.0.1" - checksum: 10c0/dfa5960e2aaf125707e19a4b1bc333de49232eba5a6ffffb95d313a7d6087c3b7a274b58bee8d3bd41bdf150638815d1d601a42bbf2a0345208c3c35b1279556 - languageName: node - linkType: hard - "parse5-htmlparser2-tree-adapter@npm:^7.0.0": version: 7.1.0 resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0" @@ -16929,7 +16727,7 @@ __metadata: languageName: node linkType: hard -"parse5@npm:6.0.1, parse5@npm:^6.0.1": +"parse5@npm:6.0.1": version: 6.0.1 resolution: "parse5@npm:6.0.1" checksum: 10c0/595821edc094ecbcfb9ddcb46a3e1fe3a718540f8320eff08b8cf6742a5114cce2d46d45f95c26191c11b184dcaf4e2960abcd9c5ed9eb9393ac9a37efcfdecb @@ -17909,32 +17707,6 @@ __metadata: languageName: node linkType: hard -"raf@npm:^3.4.1": - version: 3.4.1 - resolution: "raf@npm:3.4.1" - dependencies: - performance-now: "npm:^2.1.0" - checksum: 10c0/337f0853c9e6a77647b0f499beedafea5d6facfb9f2d488a624f88b03df2be72b8a0e7f9118a3ff811377d534912039a3311815700d2b6d2313f82f736f9eb6e - languageName: node - linkType: hard - -"railroad-diagrams@npm:^1.0.0": - version: 1.0.0 - resolution: "railroad-diagrams@npm:1.0.0" - checksum: 10c0/81bf8f86870a69fb9ed243102db9ad6416d09c4cb83964490d44717690e07dd982f671503236a1f8af28f4cb79d5d7a87613930f10ac08defa845ceb6764e364 - languageName: node - linkType: hard - -"randexp@npm:0.4.6": - version: 0.4.6 - resolution: "randexp@npm:0.4.6" - dependencies: - discontinuous-range: "npm:1.0.0" - ret: "npm:~0.1.10" - checksum: 10c0/14ee14b6d7f5ce69609b51cc914fb7a7c82ad337820a141c5f762c5ad1fe868f5191ea6e82359aee019b625ee1359486628fa833909d12c3b5dd9571908c3345 - languageName: node - linkType: hard - "randomatic@npm:^3.0.0": version: 3.1.1 resolution: "randomatic@npm:3.1.1" @@ -18123,7 +17895,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.12.0, react-is@npm:^16.13.1, react-is@npm:^16.8.6": +"react-is@npm:^16.13.1, react-is@npm:^16.8.6": version: 16.13.1 resolution: "react-is@npm:16.13.1" checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 @@ -19155,16 +18927,6 @@ __metadata: languageName: node linkType: hard -"rst-selector-parser@npm:^2.2.3": - version: 2.2.3 - resolution: "rst-selector-parser@npm:2.2.3" - dependencies: - lodash.flattendeep: "npm:^4.4.0" - nearley: "npm:^2.7.10" - checksum: 10c0/b631aca2cb451fbde8d78dbc9a9479f20f1f40565cd8eb63773cb6e2a395ed87b392291986b84c2c7da68b70084e3469fbe958261300a10dff41c87fa3bc58aa - languageName: node - linkType: hard - "rsvp@npm:^3.3.3": version: 3.6.2 resolution: "rsvp@npm:3.6.2" @@ -20601,7 +20363,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.trim@npm:^1.2.1, string.prototype.trim@npm:^1.2.7": +"string.prototype.trim@npm:^1.2.7": version: 1.2.7 resolution: "string.prototype.trim@npm:1.2.7" dependencies: @@ -21538,7 +21300,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0": +"tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0": version: 2.5.2 resolution: "tslib@npm:2.5.2" checksum: 10c0/34fa100454708fa8acb7afc2b07d80e0332081e2075ddd912ba959af3b24f969663dac6d602961e57371dc05683badb83b3186ada92c4631ec777e02e3aab608