|
|
@@ -24,20 +24,17 @@ describe('<ProjectListRoot />', function () {
|
|
|
sendSpy = sinon.spy(eventTracking, 'send')
|
|
|
window.metaAttributesCache = new Map()
|
|
|
window.metaAttributesCache.set('ol-tags', [])
|
|
|
- window.metaAttributesCache.set('ol-ExposedSettings', { templateLinks: [] })
|
|
|
+ window.metaAttributesCache.set('ol-ExposedSettings', {
|
|
|
+ templateLinks: [],
|
|
|
+ })
|
|
|
+ window.metaAttributesCache.set('ol-userEmails', [
|
|
|
+ { email: 'test@overleaf.com', default: true },
|
|
|
+ ])
|
|
|
window.user_id = userId
|
|
|
|
|
|
Object.defineProperty(window, 'location', {
|
|
|
value: { assign: locationStub },
|
|
|
})
|
|
|
-
|
|
|
- renderWithProjectListContext(<ProjectListRoot />, {
|
|
|
- projects: fullList,
|
|
|
- })
|
|
|
- await fetchMock.flush(true)
|
|
|
- await waitFor(() => {
|
|
|
- screen.findByRole('table')
|
|
|
- })
|
|
|
})
|
|
|
|
|
|
afterEach(function () {
|
|
|
@@ -49,360 +46,465 @@ describe('<ProjectListRoot />', function () {
|
|
|
})
|
|
|
})
|
|
|
|
|
|
- describe('checkboxes', function () {
|
|
|
- let allCheckboxes: Array<HTMLInputElement> = []
|
|
|
- let actionsToolbar: HTMLElement
|
|
|
- let project1Id: string | null, project2Id: string | null
|
|
|
-
|
|
|
- describe('all projects', function () {
|
|
|
- beforeEach(function () {
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[1])
|
|
|
- fireEvent.click(allCheckboxes[2])
|
|
|
-
|
|
|
- project1Id = allCheckboxes[1].getAttribute('data-project-id')
|
|
|
- project2Id = allCheckboxes[2].getAttribute('data-project-id')
|
|
|
- actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
+ describe('welcome page', function () {
|
|
|
+ beforeEach(async function () {
|
|
|
+ renderWithProjectListContext(<ProjectListRoot />, {
|
|
|
+ projects: [],
|
|
|
})
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ })
|
|
|
|
|
|
- it('downloads all selected projects and then unselects them', async function () {
|
|
|
- const downloadButton = within(actionsToolbar).getByLabelText('Download')
|
|
|
- fireEvent.click(downloadButton)
|
|
|
-
|
|
|
- await waitFor(() => {
|
|
|
- expect(locationStub).to.have.been.called
|
|
|
- })
|
|
|
+ it('the welcome page is displayed', async function () {
|
|
|
+ screen.getByRole('heading', { name: 'Welcome to Overleaf!' })
|
|
|
+ })
|
|
|
|
|
|
- sinon.assert.calledWithMatch(
|
|
|
- locationStub,
|
|
|
- `/project/download/zip?project_ids=${project1Id},${project2Id}`
|
|
|
+ it('the email confirmation alert is not displayed', async function () {
|
|
|
+ expect(
|
|
|
+ screen.queryByText(
|
|
|
+ 'Please confirm your email test@overleaf.com by clicking on the link in the confirmation email'
|
|
|
)
|
|
|
+ ).to.be.null
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
- const allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
+ describe('project table', function () {
|
|
|
+ beforeEach(async function () {
|
|
|
+ renderWithProjectListContext(<ProjectListRoot />, {
|
|
|
+ projects: fullList,
|
|
|
})
|
|
|
-
|
|
|
- it('opens archive modal for all selected projects and archives all', async function () {
|
|
|
- fetchMock.post(
|
|
|
- `express:/project/${project1Id}/archive`,
|
|
|
- {
|
|
|
- status: 200,
|
|
|
- },
|
|
|
- { delay: 0 }
|
|
|
- )
|
|
|
- fetchMock.post(
|
|
|
- `express:/project/${project2Id}/archive`,
|
|
|
- {
|
|
|
- status: 200,
|
|
|
- },
|
|
|
- { delay: 0 }
|
|
|
- )
|
|
|
-
|
|
|
- const archiveButton = within(actionsToolbar).getByLabelText('Archive')
|
|
|
- fireEvent.click(archiveButton)
|
|
|
-
|
|
|
- const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement
|
|
|
- fireEvent.click(confirmBtn)
|
|
|
- expect(confirmBtn.disabled).to.be.true
|
|
|
-
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
-
|
|
|
- const requests = fetchMock.calls()
|
|
|
- const [projectRequest1Url, projectRequest1Headers] = requests[2]
|
|
|
- expect(projectRequest1Url).to.equal(`/project/${project1Id}/archive`)
|
|
|
- expect(projectRequest1Headers?.method).to.equal('POST')
|
|
|
- const [projectRequest2Url, projectRequest2Headers] = requests[3]
|
|
|
- expect(projectRequest2Url).to.equal(`/project/${project2Id}/archive`)
|
|
|
- expect(projectRequest2Headers?.method).to.equal('POST')
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ await waitFor(() => {
|
|
|
+ screen.findByRole('table')
|
|
|
})
|
|
|
+ })
|
|
|
|
|
|
- it('opens trash modal for all selected projects and trashes all', async function () {
|
|
|
- fetchMock.post(
|
|
|
- `express:/project/${project1Id}/trash`,
|
|
|
- {
|
|
|
- status: 200,
|
|
|
- },
|
|
|
- { delay: 0 }
|
|
|
- )
|
|
|
- fetchMock.post(
|
|
|
- `express:/project/${project2Id}/trash`,
|
|
|
- {
|
|
|
- status: 200,
|
|
|
- },
|
|
|
- { delay: 0 }
|
|
|
- )
|
|
|
+ describe('checkboxes', function () {
|
|
|
+ let allCheckboxes: Array<HTMLInputElement> = []
|
|
|
+ let actionsToolbar: HTMLElement
|
|
|
+ let project1Id: string | null, project2Id: string | null
|
|
|
+
|
|
|
+ describe('all projects', function () {
|
|
|
+ beforeEach(function () {
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[1])
|
|
|
+ fireEvent.click(allCheckboxes[2])
|
|
|
+
|
|
|
+ project1Id = allCheckboxes[1].getAttribute('data-project-id')
|
|
|
+ project2Id = allCheckboxes[2].getAttribute('data-project-id')
|
|
|
+ actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
+ })
|
|
|
|
|
|
- const archiveButton = within(actionsToolbar).getByLabelText('Trash')
|
|
|
- fireEvent.click(archiveButton)
|
|
|
+ it('downloads all selected projects and then unselects them', async function () {
|
|
|
+ const downloadButton =
|
|
|
+ within(actionsToolbar).getByLabelText('Download')
|
|
|
+ fireEvent.click(downloadButton)
|
|
|
|
|
|
- const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement
|
|
|
- fireEvent.click(confirmBtn)
|
|
|
- expect(confirmBtn.disabled).to.be.true
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(locationStub).to.have.been.called
|
|
|
+ })
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ sinon.assert.calledWithMatch(
|
|
|
+ locationStub,
|
|
|
+ `/project/download/zip?project_ids=${project1Id},${project2Id}`
|
|
|
+ )
|
|
|
|
|
|
- const requests = fetchMock.calls()
|
|
|
- const [projectRequest1Url, projectRequest1Headers] = requests[2]
|
|
|
- expect(projectRequest1Url).to.equal(`/project/${project1Id}/trash`)
|
|
|
- expect(projectRequest1Headers?.method).to.equal('POST')
|
|
|
- const [projectRequest2Url, projectRequest2Headers] = requests[3]
|
|
|
- expect(projectRequest2Url).to.equal(`/project/${project2Id}/trash`)
|
|
|
- expect(projectRequest2Headers?.method).to.equal('POST')
|
|
|
- })
|
|
|
+ const allCheckboxes =
|
|
|
+ screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
+ })
|
|
|
|
|
|
- it('only checks the projects that are viewable when there is a load more button', async function () {
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[0])
|
|
|
+ it('opens archive modal for all selected projects and archives all', async function () {
|
|
|
+ fetchMock.post(
|
|
|
+ `express:/project/${project1Id}/archive`,
|
|
|
+ {
|
|
|
+ status: 200,
|
|
|
+ },
|
|
|
+ { delay: 0 }
|
|
|
+ )
|
|
|
+ fetchMock.post(
|
|
|
+ `express:/project/${project2Id}/archive`,
|
|
|
+ {
|
|
|
+ status: 200,
|
|
|
+ },
|
|
|
+ { delay: 0 }
|
|
|
+ )
|
|
|
+
|
|
|
+ const archiveButton = within(actionsToolbar).getByLabelText('Archive')
|
|
|
+ fireEvent.click(archiveButton)
|
|
|
+
|
|
|
+ const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement
|
|
|
+ fireEvent.click(confirmBtn)
|
|
|
+ expect(confirmBtn.disabled).to.be.true
|
|
|
+
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
+
|
|
|
+ const requests = fetchMock.calls()
|
|
|
+ const [projectRequest1Url, projectRequest1Headers] = requests[2]
|
|
|
+ expect(projectRequest1Url).to.equal(`/project/${project1Id}/archive`)
|
|
|
+ expect(projectRequest1Headers?.method).to.equal('POST')
|
|
|
+ const [projectRequest2Url, projectRequest2Headers] = requests[3]
|
|
|
+ expect(projectRequest2Url).to.equal(`/project/${project2Id}/archive`)
|
|
|
+ expect(projectRequest2Headers?.method).to.equal('POST')
|
|
|
+ })
|
|
|
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- let checked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(checked.length).to.equal(21) // max projects viewable by default is 20, and plus one for check all
|
|
|
+ it('opens trash modal for all selected projects and trashes all', async function () {
|
|
|
+ fetchMock.post(
|
|
|
+ `express:/project/${project1Id}/trash`,
|
|
|
+ {
|
|
|
+ status: 200,
|
|
|
+ },
|
|
|
+ { delay: 0 }
|
|
|
+ )
|
|
|
+ fetchMock.post(
|
|
|
+ `express:/project/${project2Id}/trash`,
|
|
|
+ {
|
|
|
+ status: 200,
|
|
|
+ },
|
|
|
+ { delay: 0 }
|
|
|
+ )
|
|
|
+
|
|
|
+ const archiveButton = within(actionsToolbar).getByLabelText('Trash')
|
|
|
+ fireEvent.click(archiveButton)
|
|
|
+
|
|
|
+ const confirmBtn = screen.getByText('Confirm') as HTMLButtonElement
|
|
|
+ fireEvent.click(confirmBtn)
|
|
|
+ expect(confirmBtn.disabled).to.be.true
|
|
|
+
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
+
|
|
|
+ const requests = fetchMock.calls()
|
|
|
+ const [projectRequest1Url, projectRequest1Headers] = requests[2]
|
|
|
+ expect(projectRequest1Url).to.equal(`/project/${project1Id}/trash`)
|
|
|
+ expect(projectRequest1Headers?.method).to.equal('POST')
|
|
|
+ const [projectRequest2Url, projectRequest2Headers] = requests[3]
|
|
|
+ expect(projectRequest2Url).to.equal(`/project/${project2Id}/trash`)
|
|
|
+ expect(projectRequest2Headers?.method).to.equal('POST')
|
|
|
+ })
|
|
|
|
|
|
- const loadMoreButton = screen.getByLabelText('Show 17 more projects')
|
|
|
- fireEvent.click(loadMoreButton)
|
|
|
+ it('only checks the projects that are viewable when there is a load more button', async function () {
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[0])
|
|
|
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- expect(allCheckboxes.length).to.equal(currentList.length + 1)
|
|
|
- checked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(checked.length).to.equal(20) // remains same even after showing more
|
|
|
- })
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ let checked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(checked.length).to.equal(21) // max projects viewable by default is 20, and plus one for check all
|
|
|
|
|
|
- it('maintains viewable and selected projects after loading more and then selecting all', async function () {
|
|
|
- const loadMoreButton = screen.getByLabelText('Show 17 more projects')
|
|
|
- fireEvent.click(loadMoreButton)
|
|
|
- // verify button gone
|
|
|
- screen.getByText(
|
|
|
- `Showing ${currentList.length} out of ${currentList.length} projects.`
|
|
|
- )
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[0])
|
|
|
- // verify button still gone
|
|
|
- screen.getByText(
|
|
|
- `Showing ${currentList.length} out of ${currentList.length} projects.`
|
|
|
- )
|
|
|
+ const loadMoreButton = screen.getByLabelText('Show 17 more projects')
|
|
|
+ fireEvent.click(loadMoreButton)
|
|
|
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- expect(allCheckboxes.length).to.equal(currentList.length + 1)
|
|
|
- })
|
|
|
- })
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ expect(allCheckboxes.length).to.equal(currentList.length + 1)
|
|
|
+ checked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(checked.length).to.equal(20) // remains same even after showing more
|
|
|
+ })
|
|
|
|
|
|
- describe('archived projects', function () {
|
|
|
- beforeEach(function () {
|
|
|
- const filterButton = screen.getAllByText('Archived Projects')[0]
|
|
|
- fireEvent.click(filterButton)
|
|
|
+ it('maintains viewable and selected projects after loading more and then selecting all', async function () {
|
|
|
+ const loadMoreButton = screen.getByLabelText('Show 17 more projects')
|
|
|
+ fireEvent.click(loadMoreButton)
|
|
|
+ // verify button gone
|
|
|
+ screen.getByText(
|
|
|
+ `Showing ${currentList.length} out of ${currentList.length} projects.`
|
|
|
+ )
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[0])
|
|
|
+ // verify button still gone
|
|
|
+ screen.getByText(
|
|
|
+ `Showing ${currentList.length} out of ${currentList.length} projects.`
|
|
|
+ )
|
|
|
+
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ expect(allCheckboxes.length).to.equal(currentList.length + 1)
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- expect(allCheckboxes.length === 2).to.be.true
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[1])
|
|
|
- project1Id = allCheckboxes[1].getAttribute('data-project-id')
|
|
|
+ describe('archived projects', function () {
|
|
|
+ beforeEach(function () {
|
|
|
+ const filterButton = screen.getAllByText('Archived Projects')[0]
|
|
|
+ fireEvent.click(filterButton)
|
|
|
|
|
|
- actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
- })
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ expect(allCheckboxes.length === 2).to.be.true
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[1])
|
|
|
+ project1Id = allCheckboxes[1].getAttribute('data-project-id')
|
|
|
|
|
|
- it('does not show the archive button in toolbar when archive view selected', function () {
|
|
|
- expect(screen.queryByLabelText('Archive')).to.be.null
|
|
|
- })
|
|
|
+ actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
+ })
|
|
|
|
|
|
- it('restores all projects when selected', async function () {
|
|
|
- fetchMock.delete(`express:/project/:id/archive`, {
|
|
|
- status: 200,
|
|
|
+ it('does not show the archive button in toolbar when archive view selected', function () {
|
|
|
+ expect(screen.queryByLabelText('Archive')).to.be.null
|
|
|
})
|
|
|
|
|
|
- const unarchiveButton =
|
|
|
- within(actionsToolbar).getByText<HTMLInputElement>('Restore')
|
|
|
- fireEvent.click(unarchiveButton)
|
|
|
+ it('restores all projects when selected', async function () {
|
|
|
+ fetchMock.delete(`express:/project/:id/archive`, {
|
|
|
+ status: 200,
|
|
|
+ })
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ const unarchiveButton =
|
|
|
+ within(actionsToolbar).getByText<HTMLInputElement>('Restore')
|
|
|
+ fireEvent.click(unarchiveButton)
|
|
|
|
|
|
- screen.getByText('No projects')
|
|
|
- })
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
|
|
|
- it('only unarchive the selected projects', async function () {
|
|
|
- // beforeEach selected all, so uncheck the 1st project
|
|
|
- fireEvent.click(allCheckboxes[1])
|
|
|
+ screen.getByText('No projects')
|
|
|
+ })
|
|
|
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(allCheckboxesChecked.length).to.equal(
|
|
|
- archivedProjects.length - 1
|
|
|
- )
|
|
|
+ it('only unarchive the selected projects', async function () {
|
|
|
+ // beforeEach selected all, so uncheck the 1st project
|
|
|
+ fireEvent.click(allCheckboxes[1])
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(
|
|
|
+ archivedProjects.length - 1
|
|
|
+ )
|
|
|
|
|
|
- expect(screen.queryByText('No projects')).to.be.null
|
|
|
- })
|
|
|
- })
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
|
|
|
- describe('trashed projects', function () {
|
|
|
- beforeEach(function () {
|
|
|
- const filterButton = screen.getAllByText('Trashed Projects')[0]
|
|
|
- fireEvent.click(filterButton)
|
|
|
+ expect(screen.queryByText('No projects')).to.be.null
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- // + 1 because of select all
|
|
|
- expect(allCheckboxes.length).to.equal(trashedList.length + 1)
|
|
|
+ describe('trashed projects', function () {
|
|
|
+ beforeEach(function () {
|
|
|
+ const filterButton = screen.getAllByText('Trashed Projects')[0]
|
|
|
+ fireEvent.click(filterButton)
|
|
|
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[0])
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ // + 1 because of select all
|
|
|
+ expect(allCheckboxes.length).to.equal(trashedList.length + 1)
|
|
|
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- // + 1 because of select all
|
|
|
- expect(allCheckboxesChecked.length).to.equal(trashedList.length + 1)
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[0])
|
|
|
|
|
|
- actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
- })
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ // + 1 because of select all
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(trashedList.length + 1)
|
|
|
|
|
|
- it('only shows the download, archive, and restore buttons in top toolbar', function () {
|
|
|
- expect(screen.queryByLabelText('Trash')).to.be.null
|
|
|
- within(actionsToolbar).queryByLabelText('Download')
|
|
|
- within(actionsToolbar).queryByLabelText('Archive')
|
|
|
- within(actionsToolbar).getByText('Restore') // no icon for this button
|
|
|
- })
|
|
|
+ actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
+ })
|
|
|
|
|
|
- it('clears selected projects when filter changed', function () {
|
|
|
- const filterButton = screen.getAllByText('All Projects')[0]
|
|
|
- fireEvent.click(filterButton)
|
|
|
+ it('only shows the download, archive, and restore buttons in top toolbar', function () {
|
|
|
+ expect(screen.queryByLabelText('Trash')).to.be.null
|
|
|
+ within(actionsToolbar).queryByLabelText('Download')
|
|
|
+ within(actionsToolbar).queryByLabelText('Archive')
|
|
|
+ within(actionsToolbar).getByText('Restore') // no icon for this button
|
|
|
+ })
|
|
|
|
|
|
- const allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
- })
|
|
|
+ it('clears selected projects when filter changed', function () {
|
|
|
+ const filterButton = screen.getAllByText('All Projects')[0]
|
|
|
+ fireEvent.click(filterButton)
|
|
|
|
|
|
- it('untrashes all the projects', async function () {
|
|
|
- fetchMock.delete(`express:/project/:id/trash`, {
|
|
|
- status: 200,
|
|
|
+ const allCheckboxes =
|
|
|
+ screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
})
|
|
|
|
|
|
- const untrashButton =
|
|
|
- within(actionsToolbar).getByText<HTMLInputElement>('Restore')
|
|
|
- fireEvent.click(untrashButton)
|
|
|
+ it('untrashes all the projects', async function () {
|
|
|
+ fetchMock.delete(`express:/project/:id/trash`, {
|
|
|
+ status: 200,
|
|
|
+ })
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ const untrashButton =
|
|
|
+ within(actionsToolbar).getByText<HTMLInputElement>('Restore')
|
|
|
+ fireEvent.click(untrashButton)
|
|
|
|
|
|
- screen.getByText('No projects')
|
|
|
- })
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
|
|
|
- it('only untrashes the selected projects', async function () {
|
|
|
- // beforeEach selected all, so uncheck the 1st project
|
|
|
- fireEvent.click(allCheckboxes[1])
|
|
|
+ screen.getByText('No projects')
|
|
|
+ })
|
|
|
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(allCheckboxesChecked.length).to.equal(trashedList.length - 1)
|
|
|
+ it('only untrashes the selected projects', async function () {
|
|
|
+ // beforeEach selected all, so uncheck the 1st project
|
|
|
+ fireEvent.click(allCheckboxes[1])
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(trashedList.length - 1)
|
|
|
|
|
|
- expect(screen.queryByText('No projects')).to.be.null
|
|
|
- })
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
|
|
|
- it('removes project from view when archiving', async function () {
|
|
|
- fetchMock.post(`express:/project/:id/archive`, {
|
|
|
- status: 200,
|
|
|
+ expect(screen.queryByText('No projects')).to.be.null
|
|
|
})
|
|
|
|
|
|
- const untrashButton =
|
|
|
- within(actionsToolbar).getByLabelText<HTMLInputElement>('Archive')
|
|
|
- fireEvent.click(untrashButton)
|
|
|
-
|
|
|
- const confirmButton = screen.getByText<HTMLInputElement>('Confirm')
|
|
|
- fireEvent.click(confirmButton)
|
|
|
- expect(confirmButton.disabled).to.be.true
|
|
|
+ it('removes project from view when archiving', async function () {
|
|
|
+ fetchMock.post(`express:/project/:id/archive`, {
|
|
|
+ status: 200,
|
|
|
+ })
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ const untrashButton =
|
|
|
+ within(actionsToolbar).getByLabelText<HTMLInputElement>('Archive')
|
|
|
+ fireEvent.click(untrashButton)
|
|
|
|
|
|
- screen.getByText('No projects')
|
|
|
- })
|
|
|
- })
|
|
|
+ const confirmButton = screen.getByText<HTMLInputElement>('Confirm')
|
|
|
+ fireEvent.click(confirmButton)
|
|
|
+ expect(confirmButton.disabled).to.be.true
|
|
|
|
|
|
- describe('project tools "More" dropdown', function () {
|
|
|
- beforeEach(async function () {
|
|
|
- const filterButton = screen.getAllByText('All Projects')[0]
|
|
|
- fireEvent.click(filterButton)
|
|
|
- allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- // first one is the select all checkbox
|
|
|
- fireEvent.click(allCheckboxes[2])
|
|
|
- actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
- })
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
|
|
|
- it('does not show the dropdown when more than 1 project is selected', async function () {
|
|
|
- await waitFor(() => {
|
|
|
- within(actionsToolbar).getByText<HTMLElement>('More')
|
|
|
+ screen.getByText('No projects')
|
|
|
})
|
|
|
- fireEvent.click(allCheckboxes[0])
|
|
|
- expect(within(actionsToolbar).queryByText<HTMLElement>('More')).to.be
|
|
|
- .null
|
|
|
})
|
|
|
|
|
|
- it('opens the rename modal, and can rename the project, and view updated', async function () {
|
|
|
- fetchMock.post(`express:/project/:id/rename`, {
|
|
|
- status: 200,
|
|
|
+ describe('project tools "More" dropdown', function () {
|
|
|
+ beforeEach(async function () {
|
|
|
+ const filterButton = screen.getAllByText('All Projects')[0]
|
|
|
+ fireEvent.click(filterButton)
|
|
|
+ allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ // first one is the select all checkbox
|
|
|
+ fireEvent.click(allCheckboxes[2])
|
|
|
+ actionsToolbar = screen.getAllByRole('toolbar')[0]
|
|
|
})
|
|
|
|
|
|
- await waitFor(() => {
|
|
|
- const moreDropdown =
|
|
|
+ it('does not show the dropdown when more than 1 project is selected', async function () {
|
|
|
+ await waitFor(() => {
|
|
|
within(actionsToolbar).getByText<HTMLElement>('More')
|
|
|
- fireEvent.click(moreDropdown)
|
|
|
+ })
|
|
|
+ fireEvent.click(allCheckboxes[0])
|
|
|
+ expect(within(actionsToolbar).queryByText<HTMLElement>('More')).to.be
|
|
|
+ .null
|
|
|
})
|
|
|
|
|
|
- const renameButton = screen.getByText<HTMLInputElement>('Rename')
|
|
|
- fireEvent.click(renameButton)
|
|
|
-
|
|
|
- const modal = screen.getAllByRole('dialog')[0]
|
|
|
-
|
|
|
- expect(sendSpy).to.be.calledOnce
|
|
|
- expect(sendSpy).calledWith('project-list-page-interaction')
|
|
|
-
|
|
|
- // same name
|
|
|
- let confirmButton = within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
- expect(confirmButton.disabled).to.be.true
|
|
|
- let input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
- const oldName = input.value
|
|
|
-
|
|
|
- // no name
|
|
|
- let newProjectName = ''
|
|
|
- input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
- fireEvent.change(input, {
|
|
|
- target: { value: newProjectName },
|
|
|
- })
|
|
|
- confirmButton = within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
- expect(confirmButton.disabled).to.be.true
|
|
|
-
|
|
|
- // a valid name
|
|
|
- newProjectName = 'A new project name'
|
|
|
- input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
- fireEvent.change(input, {
|
|
|
- target: { value: newProjectName },
|
|
|
+ it('opens the rename modal, and can rename the project, and view updated', async function () {
|
|
|
+ fetchMock.post(`express:/project/:id/rename`, {
|
|
|
+ status: 200,
|
|
|
+ })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const moreDropdown =
|
|
|
+ within(actionsToolbar).getByText<HTMLElement>('More')
|
|
|
+ fireEvent.click(moreDropdown)
|
|
|
+ })
|
|
|
+
|
|
|
+ const renameButton = screen.getByText<HTMLInputElement>('Rename')
|
|
|
+ fireEvent.click(renameButton)
|
|
|
+
|
|
|
+ const modal = screen.getAllByRole('dialog')[0]
|
|
|
+
|
|
|
+ expect(sendSpy).to.be.calledOnce
|
|
|
+ expect(sendSpy).calledWith('project-list-page-interaction')
|
|
|
+
|
|
|
+ // same name
|
|
|
+ let confirmButton =
|
|
|
+ within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
+ expect(confirmButton.disabled).to.be.true
|
|
|
+ let input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
+ const oldName = input.value
|
|
|
+
|
|
|
+ // no name
|
|
|
+ let newProjectName = ''
|
|
|
+ input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
+ fireEvent.change(input, {
|
|
|
+ target: { value: newProjectName },
|
|
|
+ })
|
|
|
+ confirmButton = within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
+ expect(confirmButton.disabled).to.be.true
|
|
|
+
|
|
|
+ // a valid name
|
|
|
+ newProjectName = 'A new project name'
|
|
|
+ input = screen.getByLabelText('New Name') as HTMLButtonElement
|
|
|
+ fireEvent.change(input, {
|
|
|
+ target: { value: newProjectName },
|
|
|
+ })
|
|
|
+
|
|
|
+ confirmButton = within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
+ expect(confirmButton.disabled).to.be.false
|
|
|
+ fireEvent.click(confirmButton)
|
|
|
+
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
+
|
|
|
+ screen.findByText(newProjectName)
|
|
|
+ expect(screen.queryByText(oldName)).to.be.null
|
|
|
+
|
|
|
+ const allCheckboxes =
|
|
|
+ screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
+ const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
+ expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
})
|
|
|
|
|
|
- confirmButton = within(modal).getByText<HTMLInputElement>('Rename')
|
|
|
- expect(confirmButton.disabled).to.be.false
|
|
|
- fireEvent.click(confirmButton)
|
|
|
+ it('opens the copy modal, can copy the project, and view updated', async function () {
|
|
|
+ const tableRows = screen.getAllByRole('row')
|
|
|
+ const linkForProjectToCopy = within(tableRows[1]).getByRole('link')
|
|
|
+ const projectNameToCopy = linkForProjectToCopy.textContent || '' // needed for type checking
|
|
|
+ screen.findByText(projectNameToCopy) // make sure not just empty string
|
|
|
+ const copiedProjectName = `${projectNameToCopy} (Copy)`
|
|
|
+ fetchMock.post(`express:/project/:id/clone`, {
|
|
|
+ status: 200,
|
|
|
+ body: {
|
|
|
+ name: copiedProjectName,
|
|
|
+ lastUpdated: new Date(),
|
|
|
+ project_id: userId,
|
|
|
+ owner_ref: userId,
|
|
|
+ owner,
|
|
|
+ id: '6328e14abec0df019fce0be5',
|
|
|
+ lastUpdatedBy: owner,
|
|
|
+ accessLevel: 'owner',
|
|
|
+ source: 'owner',
|
|
|
+ trashed: false,
|
|
|
+ archived: false,
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ const moreDropdown =
|
|
|
+ within(actionsToolbar).getByText<HTMLElement>('More')
|
|
|
+ fireEvent.click(moreDropdown)
|
|
|
+ })
|
|
|
+
|
|
|
+ const copyButton =
|
|
|
+ within(actionsToolbar).getByText<HTMLInputElement>('Make a copy')
|
|
|
+ fireEvent.click(copyButton)
|
|
|
+
|
|
|
+ // confirm in modal
|
|
|
+ const copyConfirmButton = document.querySelector(
|
|
|
+ 'button[type="submit"]'
|
|
|
+ ) as HTMLElement
|
|
|
+ fireEvent.click(copyConfirmButton)
|
|
|
+
|
|
|
+ await fetchMock.flush(true)
|
|
|
+ expect(fetchMock.done()).to.be.true
|
|
|
+
|
|
|
+ expect(sendSpy).to.be.calledOnce
|
|
|
+ expect(sendSpy).calledWith('project-list-page-interaction')
|
|
|
+
|
|
|
+ screen.findByText(copiedProjectName)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
+ describe('search', function () {
|
|
|
+ it('shows only projects based on the input', async function () {
|
|
|
+ const input = screen.getAllByRole('textbox', {
|
|
|
+ name: /search projects/i,
|
|
|
+ })[0]
|
|
|
+ const value = currentList[0].name
|
|
|
|
|
|
- screen.findByText(newProjectName)
|
|
|
- expect(screen.queryByText(oldName)).to.be.null
|
|
|
+ fireEvent.change(input, { target: { value } })
|
|
|
|
|
|
- const allCheckboxes = screen.getAllByRole<HTMLInputElement>('checkbox')
|
|
|
- const allCheckboxesChecked = allCheckboxes.filter(c => c.checked)
|
|
|
- expect(allCheckboxesChecked.length).to.equal(0)
|
|
|
+ const results = screen.getAllByRole('row')
|
|
|
+ expect(results.length).to.equal(2) // first is header
|
|
|
})
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('copying project', function () {
|
|
|
+ it('correctly updates the view after copying a shared project', async function () {
|
|
|
+ const filterButton = screen.getAllByText('Shared with you')[0]
|
|
|
+ fireEvent.click(filterButton)
|
|
|
|
|
|
- it('opens the copy modal, can copy the project, and view updated', async function () {
|
|
|
const tableRows = screen.getAllByRole('row')
|
|
|
+
|
|
|
const linkForProjectToCopy = within(tableRows[1]).getByRole('link')
|
|
|
- const projectNameToCopy = linkForProjectToCopy.textContent || '' // needed for type checking
|
|
|
- screen.findByText(projectNameToCopy) // make sure not just empty string
|
|
|
- const copiedProjectName = `${projectNameToCopy} (Copy)`
|
|
|
+ const projectNameToCopy = linkForProjectToCopy.textContent
|
|
|
+ const copiedProjectName = `${projectNameToCopy} Copy`
|
|
|
fetchMock.post(`express:/project/:id/clone`, {
|
|
|
status: 200,
|
|
|
body: {
|
|
|
@@ -419,15 +521,7 @@ describe('<ProjectListRoot />', function () {
|
|
|
archived: false,
|
|
|
},
|
|
|
})
|
|
|
-
|
|
|
- await waitFor(() => {
|
|
|
- const moreDropdown =
|
|
|
- within(actionsToolbar).getByText<HTMLElement>('More')
|
|
|
- fireEvent.click(moreDropdown)
|
|
|
- })
|
|
|
-
|
|
|
- const copyButton =
|
|
|
- within(actionsToolbar).getByText<HTMLInputElement>('Make a copy')
|
|
|
+ const copyButton = within(tableRows[1]).getAllByLabelText('Copy')[0]
|
|
|
fireEvent.click(copyButton)
|
|
|
|
|
|
// confirm in modal
|
|
|
@@ -442,71 +536,20 @@ describe('<ProjectListRoot />', function () {
|
|
|
expect(sendSpy).to.be.calledOnce
|
|
|
expect(sendSpy).calledWith('project-list-page-interaction')
|
|
|
|
|
|
+ expect(screen.queryByText(copiedProjectName)).to.be.null
|
|
|
+
|
|
|
+ const yourProjectFilter = screen.getAllByText('Your Projects')[0]
|
|
|
+ fireEvent.click(yourProjectFilter)
|
|
|
screen.findByText(copiedProjectName)
|
|
|
})
|
|
|
})
|
|
|
- })
|
|
|
-
|
|
|
- describe('search', function () {
|
|
|
- it('shows only projects based on the input', async function () {
|
|
|
- const input = screen.getAllByRole('textbox', {
|
|
|
- name: /search projects/i,
|
|
|
- })[0]
|
|
|
- const value = currentList[0].name
|
|
|
-
|
|
|
- fireEvent.change(input, { target: { value } })
|
|
|
-
|
|
|
- const results = screen.getAllByRole('row')
|
|
|
- expect(results.length).to.equal(2) // first is header
|
|
|
- })
|
|
|
- })
|
|
|
|
|
|
- describe('copying project', function () {
|
|
|
- it('correctly updates the view after copying a shared project', async function () {
|
|
|
- const filterButton = screen.getAllByText('Shared with you')[0]
|
|
|
- fireEvent.click(filterButton)
|
|
|
-
|
|
|
- const tableRows = screen.getAllByRole('row')
|
|
|
-
|
|
|
- const linkForProjectToCopy = within(tableRows[1]).getByRole('link')
|
|
|
- const projectNameToCopy = linkForProjectToCopy.textContent
|
|
|
- const copiedProjectName = `${projectNameToCopy} Copy`
|
|
|
- fetchMock.post(`express:/project/:id/clone`, {
|
|
|
- status: 200,
|
|
|
- body: {
|
|
|
- name: copiedProjectName,
|
|
|
- lastUpdated: new Date(),
|
|
|
- project_id: userId,
|
|
|
- owner_ref: userId,
|
|
|
- owner,
|
|
|
- id: '6328e14abec0df019fce0be5',
|
|
|
- lastUpdatedBy: owner,
|
|
|
- accessLevel: 'owner',
|
|
|
- source: 'owner',
|
|
|
- trashed: false,
|
|
|
- archived: false,
|
|
|
- },
|
|
|
+ describe('notifications', function () {
|
|
|
+ it('email confirmation alert is displayed', async function () {
|
|
|
+ screen.getByText(
|
|
|
+ 'Please confirm your email test@overleaf.com by clicking on the link in the confirmation email'
|
|
|
+ )
|
|
|
})
|
|
|
- const copyButton = within(tableRows[1]).getAllByLabelText('Copy')[0]
|
|
|
- fireEvent.click(copyButton)
|
|
|
-
|
|
|
- // confirm in modal
|
|
|
- const copyConfirmButton = document.querySelector(
|
|
|
- 'button[type="submit"]'
|
|
|
- ) as HTMLElement
|
|
|
- fireEvent.click(copyConfirmButton)
|
|
|
-
|
|
|
- await fetchMock.flush(true)
|
|
|
- expect(fetchMock.done()).to.be.true
|
|
|
-
|
|
|
- expect(sendSpy).to.be.calledOnce
|
|
|
- expect(sendSpy).calledWith('project-list-page-interaction')
|
|
|
-
|
|
|
- expect(screen.queryByText(copiedProjectName)).to.be.null
|
|
|
-
|
|
|
- const yourProjectFilter = screen.getAllByText('Your Projects')[0]
|
|
|
- fireEvent.click(yourProjectFilter)
|
|
|
- screen.findByText(copiedProjectName)
|
|
|
})
|
|
|
})
|
|
|
})
|