Skip to content

Commit 66b1ad9

Browse files
committed
test(ui-pages): migrate old Pages tests
1 parent 359b73c commit 66b1ad9

File tree

5 files changed

+172
-74
lines changed

5 files changed

+172
-74
lines changed

cypress/component/Page.cy.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2015 - present Instructure, Inc.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
import React, { useState } from 'react'
25+
import { Pages, PagesPage } from '@instructure/ui-pages'
26+
27+
import '../support/component'
28+
import 'cypress-real-events'
29+
30+
describe('<Page/>', () => {
31+
it('should focus default element', async () => {
32+
const Example = () => {
33+
const [activePageIndex, setActivePageIndex] = useState(0)
34+
let inputRef
35+
36+
const handleNextPageClick = () => {
37+
setActivePageIndex(1)
38+
}
39+
40+
const handleBackButtonClick = () => {
41+
setActivePageIndex(0)
42+
}
43+
44+
return (
45+
<Pages activePageIndex={activePageIndex} onPageIndexChange={cy.spy()}>
46+
<PagesPage defaultFocusElement={() => inputRef}>
47+
<button onClick={handleNextPageClick}> Next Page </button>
48+
</PagesPage>
49+
50+
<PagesPage defaultFocusElement={() => inputRef}>
51+
<input type="text" />
52+
<input
53+
id="default-input"
54+
type="text"
55+
ref={(el) => {
56+
inputRef = el
57+
}}
58+
/>
59+
<input type="text" />
60+
<button onClick={handleBackButtonClick}> Back </button>
61+
</PagesPage>
62+
</Pages>
63+
)
64+
}
65+
66+
cy.mount(<Example />)
67+
68+
cy.contains('button', 'Next Page').click()
69+
70+
cy.get('#default-input').should('be.focused')
71+
})
72+
})

package-lock.json

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ui-pages/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
"@instructure/ui-babel-preset": "10.11.0",
2727
"@instructure/ui-color-utils": "10.11.0",
2828
"@instructure/ui-test-utils": "10.11.0",
29-
"@instructure/ui-themes": "10.11.0"
29+
"@instructure/ui-themes": "10.11.0",
30+
"@testing-library/jest-dom": "^6.6.3",
31+
"@testing-library/react": "^16.0.1",
32+
"@testing-library/user-event": "^14.5.2",
33+
"vitest": "^2.1.8"
3034
},
3135
"dependencies": {
3236
"@babel/runtime": "^7.26.0",

packages/ui-pages/src/Pages/Page/__tests__/Page.test.tsx renamed to packages/ui-pages/src/Pages/Page/__new-tests__/Page.test.tsx

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,66 +23,41 @@
2323
*/
2424

2525
import React from 'react'
26-
import { expect, mount, within } from '@instructure/ui-test-utils'
26+
import { render } from '@testing-library/react'
27+
import { vi, expect } from 'vitest'
28+
import type { MockInstance } from 'vitest'
29+
30+
import '@testing-library/jest-dom'
2731
import { Page } from '../index'
2832

29-
describe('<Page />', async () => {
30-
let _input: HTMLInputElement | null
33+
describe('<Page />', () => {
34+
let consoleErrorMock: ReturnType<typeof vi.spyOn>
3135

32-
it('should render with a function as child', async () => {
33-
const subject = await mount(
34-
<Page
35-
defaultFocusElement={() => {
36-
return _input
37-
}}
38-
>
39-
{() => {
40-
return (
41-
<div>
42-
<input
43-
type="text"
44-
ref={(el) => {
45-
_input = el
46-
}}
47-
/>
48-
<span>Hello World</span>
49-
</div>
50-
)
51-
}}
52-
</Page>
53-
)
36+
beforeEach(() => {
37+
// Mocking console to prevent test output pollution
38+
consoleErrorMock = vi
39+
.spyOn(console, 'error')
40+
.mockImplementation(() => {}) as MockInstance
41+
})
5442

55-
expect(subject.getDOMNode().textContent).to.equal('Hello World')
43+
afterEach(() => {
44+
consoleErrorMock.mockRestore()
5645
})
5746

58-
it('should focus default element', async () => {
59-
const subject = await mount(
60-
<Page
61-
defaultFocusElement={() => {
62-
return _input
63-
}}
64-
>
47+
it('should render with a function as child', async () => {
48+
const { container } = render(
49+
<Page>
6550
{() => {
6651
return (
6752
<div>
68-
<input
69-
type="text"
70-
ref={(el) => {
71-
_input = el
72-
}}
73-
/>
53+
<input type="text" />
7454
<span>Hello World</span>
7555
</div>
7656
)
7757
}}
7858
</Page>
7959
)
8060

81-
const page = within(subject.getDOMNode())
82-
const input = await page.find(':focusable')
83-
84-
await page.focus()
85-
86-
expect(input.focused()).to.be.true()
61+
expect(container).toHaveTextContent('Hello World')
8762
})
8863
})

packages/ui-pages/src/Pages/__tests__/Pages.test.tsx renamed to packages/ui-pages/src/Pages/__new-tests__/Pages.test.tsx

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,81 +23,115 @@
2323
*/
2424

2525
import React from 'react'
26-
import { expect, mount, spy, within, stub } from '@instructure/ui-test-utils'
26+
import { render, waitFor } from '@testing-library/react'
27+
import { vi, expect } from 'vitest'
28+
import type { MockInstance } from 'vitest'
29+
30+
import '@testing-library/jest-dom'
31+
import userEvent from '@testing-library/user-event'
2732
import { Pages, Page } from '../index'
2833

29-
describe('<Pages />', async () => {
34+
describe('<Pages />', () => {
35+
let consoleErrorMock: ReturnType<typeof vi.spyOn>
36+
37+
beforeEach(() => {
38+
// Mocking console to prevent test output pollution and expect for messages
39+
consoleErrorMock = vi
40+
.spyOn(console, 'error')
41+
.mockImplementation(() => {}) as MockInstance
42+
})
43+
44+
afterEach(() => {
45+
consoleErrorMock.mockRestore()
46+
})
47+
3048
it('should render', async () => {
31-
const subject = await mount(
49+
const { container } = render(
3250
<Pages>
3351
<Page>{() => 'Foo'}</Page>
3452
<Page>{() => 'Bar'}</Page>
3553
</Pages>
3654
)
55+
const pages = container.querySelector('div[id^="Pages_"]')
3756

38-
expect(subject.getDOMNode()).to.exist()
57+
expect(pages).toBeInTheDocument()
3958
})
4059

4160
it('should render a Page', async () => {
42-
const subject = await mount(
61+
const { container } = render(
4362
<Pages>
4463
<Page>{() => 'Hello World'}</Page>
4564
</Pages>
4665
)
66+
const pages = container.querySelector('div[id^="Pages_"]')
4767

48-
expect(subject.getDOMNode().textContent).to.equal('Hello World')
68+
expect(pages).toHaveTextContent('Hello World')
4969
})
5070

5171
it('should render the 0th Page by default', async () => {
52-
const subject = await mount(
72+
const { container } = render(
5373
<Pages>
5474
<Page>{() => 'Foo'}</Page>
5575
<Page>{() => 'Bar'}</Page>
5676
</Pages>
5777
)
58-
expect(subject.getDOMNode().textContent).to.equal('Foo')
78+
const pages = container.querySelector('div[id^="Pages_"]')
79+
80+
expect(pages).toHaveTextContent('Foo')
5981
})
6082

6183
it('should render the active Page', async () => {
62-
const subject = await mount(
84+
const { container } = render(
6385
<Pages activePageIndex={1} onPageIndexChange={() => {}}>
6486
<Page>{() => 'Foo'}</Page>
6587
<Page>{() => 'Bar'}</Page>
6688
</Pages>
6789
)
90+
const pages = container.querySelector('div[id^="Pages_"]')
6891

69-
expect(subject.getDOMNode().textContent).to.equal('Bar')
92+
expect(pages).toHaveTextContent('Bar')
7093
})
7194

7295
it('should throw error if onPageIndexChange is not passed together with activePageIndex', async () => {
73-
const consoleError = stub(console, 'error')
74-
await mount(
96+
render(
7597
<Pages activePageIndex={1}>
7698
<Page>{() => 'Foo'}</Page>
7799
<Page>{() => 'Bar'}</Page>
78100
</Pages>
79101
)
80102

81-
expect(consoleError).to.have.been.called()
103+
const expectedErrorMessage =
104+
"You provided a 'activePageIndex' prop without an 'onPageIndexChange' handler on 'Pages'."
105+
106+
expect(consoleErrorMock).toHaveBeenCalledWith(
107+
expect.any(String),
108+
expect.any(String),
109+
expect.stringContaining(expectedErrorMessage),
110+
expect.any(String)
111+
)
82112
})
83113

84114
it('should pass history and navigateToPreviousPage to Page', async () => {
85-
const pageSpy = spy()
86-
await mount(
115+
const pageSpy = vi.fn()
116+
render(
87117
<Pages>
88118
<Page>{pageSpy}</Page>
89119
</Pages>
90120
)
91-
// Called twice because props.makeStyles() is called in Pages.componentDidMount()
92-
expect(pageSpy).to.have.been.called()
93-
expect(Array.isArray(pageSpy.args[0][0])).to.equal(true)
94-
expect(typeof pageSpy.args[0][1]).to.equal('function')
121+
122+
await waitFor(() => {
123+
const args = pageSpy.mock.calls[0]
124+
125+
expect(pageSpy).toHaveBeenCalledTimes(1)
126+
expect(Array.isArray(args[0])).toEqual(true)
127+
expect(typeof args[1]).toBe('function')
128+
})
95129
})
96130

97131
it('should fire onPageIndexChange event', async () => {
98-
const onPageIndexChange = spy()
132+
const onPageIndexChange = vi.fn()
99133

100-
const subject = await mount(
134+
const { container, rerender } = render(
101135
<Pages activePageIndex={0} onPageIndexChange={onPageIndexChange}>
102136
<Page key={0}>{() => 'Foo'}</Page>
103137
<Page key={1}>
@@ -106,14 +140,23 @@ describe('<Pages />', async () => {
106140
</Pages>
107141
)
108142

109-
await subject.setProps({ activePageIndex: 1 })
143+
// Set prop: activePageIndex
144+
rerender(
145+
<Pages activePageIndex={1} onPageIndexChange={onPageIndexChange}>
146+
<Page key={0}>{() => 'Foo'}</Page>
147+
<Page key={1}>
148+
{(_history, navigate) => <button onClick={navigate}>Back</button>}
149+
</Page>
150+
</Pages>
151+
)
110152

111-
const pages = within(subject.getDOMNode())
112-
const button = await pages.find('button')
153+
const button = container.querySelector('button')!
113154

114-
await button.click()
155+
userEvent.click(button)
115156

116-
expect(onPageIndexChange).to.have.been.calledOnce()
117-
expect(onPageIndexChange).to.have.been.calledWith(0, 1)
157+
await waitFor(() => {
158+
expect(onPageIndexChange).toHaveBeenCalledTimes(1)
159+
expect(onPageIndexChange).toHaveBeenCalledWith(0, 1)
160+
})
118161
})
119162
})

0 commit comments

Comments
 (0)