Update selectors to improve CE test stability (#28096)
* Update selectors to improve test stability * Update selectors to improve test stability * Use plain string matchers * Fix test * [monorepo] use plain string matchers everywhere * [web] remove Kb/ prefix from title of learn wiki links --------- Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com> GitOrigin-RevId: 12e13c39822795338a3bee20236454f9948e6221
This commit is contained in:
@@ -10,7 +10,7 @@ describe('Accounts', function () {
|
||||
login('user@example.com')
|
||||
cy.visit('/project')
|
||||
cy.findByRole('menuitem', { name: 'Account' }).click()
|
||||
cy.findByText('Log Out').click()
|
||||
cy.findByRole('menuitem', { name: 'Log Out' }).click()
|
||||
cy.url().should('include', '/login')
|
||||
cy.visit('/project')
|
||||
cy.url().should('include', '/login')
|
||||
|
||||
+109
-69
@@ -14,7 +14,7 @@ describe('admin panel', function () {
|
||||
function registrationTests() {
|
||||
it('via GUI and opening URL manually', () => {
|
||||
const user = `${uuid()}@example.com`
|
||||
cy.get('input[name="email"]').type(user + '{enter}')
|
||||
cy.findByLabelText('Emails to register new users').type(user + '{enter}')
|
||||
|
||||
cy.get('td')
|
||||
.contains(/\/user\/activate/)
|
||||
@@ -26,7 +26,7 @@ describe('admin panel', function () {
|
||||
|
||||
it('via GUI and email', () => {
|
||||
const user = `${uuid()}@example.com`
|
||||
cy.get('input[name="email"]').type(user + '{enter}')
|
||||
cy.findByLabelText('Emails to register new users').type(user + '{enter}')
|
||||
|
||||
let url: string
|
||||
cy.get('td')
|
||||
@@ -93,8 +93,8 @@ describe('admin panel', function () {
|
||||
beforeEach(() => {
|
||||
login(admin)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Admin').click()
|
||||
cy.get('nav').findByText('Manage Users').click()
|
||||
cy.findByRole('menuitem', { name: 'Admin' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Manage Users' }).click()
|
||||
})
|
||||
registrationTests()
|
||||
})
|
||||
@@ -139,17 +139,17 @@ describe('admin panel', function () {
|
||||
beforeEach(() => {
|
||||
login(admin)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Admin').click()
|
||||
cy.get('nav').findByText('Manage Site').click()
|
||||
cy.findByRole('menuitem', { name: 'Admin' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Manage Site' }).click()
|
||||
})
|
||||
|
||||
it('publish and clear admin messages', () => {
|
||||
const message = 'Admin Message ' + uuid()
|
||||
|
||||
cy.log('create system message')
|
||||
cy.get('[role="tab"]').contains('System Messages').click()
|
||||
cy.get('input[name="content"]').type(message)
|
||||
cy.get('button').contains('Post Message').click()
|
||||
cy.findByRole('tab', { name: 'System Messages' }).click()
|
||||
cy.findByLabelText('Message').type(message)
|
||||
cy.findByRole('button', { name: 'Post Message' }).click()
|
||||
cy.findByText(message)
|
||||
|
||||
login(user1)
|
||||
@@ -159,10 +159,10 @@ describe('admin panel', function () {
|
||||
cy.log('clear system messages')
|
||||
login(admin)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Admin').click()
|
||||
cy.get('nav').findByText('Manage Site').click()
|
||||
cy.get('[role="tab"]').contains('System Messages').click()
|
||||
cy.get('button').contains('Clear all messages').click()
|
||||
cy.findByRole('menuitem', { name: 'Admin' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Manage Site' }).click()
|
||||
cy.findByRole('tab', { name: 'System Messages' }).click()
|
||||
cy.findByRole('button', { name: 'Clear all messages' }).click()
|
||||
|
||||
cy.log('verify system messages are no longer displayed')
|
||||
login(user1)
|
||||
@@ -175,16 +175,16 @@ describe('admin panel', function () {
|
||||
beforeEach(() => {
|
||||
login(admin)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Admin').click()
|
||||
cy.get('nav').findByText('Manage Users').click()
|
||||
cy.findByRole('menuitem', { name: 'Admin' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Manage Users' }).click()
|
||||
})
|
||||
|
||||
it('displays expected tabs', () => {
|
||||
const tabs = ['Users', 'License Usage']
|
||||
cy.get('[role="tab"]').each((el, index) => {
|
||||
cy.wrap(el).findByText(tabs[index]).click()
|
||||
cy.findAllByRole('tab').should('have.length', tabs.length)
|
||||
tabs.forEach(tabName => {
|
||||
cy.findByRole('tab', { name: tabName }).click()
|
||||
})
|
||||
cy.get('[role="tab"]').should('have.length', tabs.length)
|
||||
})
|
||||
|
||||
it('license usage tab', () => {
|
||||
@@ -202,10 +202,12 @@ describe('admin panel', function () {
|
||||
})
|
||||
|
||||
it('user list RegExp search', () => {
|
||||
cy.get('input[name="isRegExpSearch"]').click()
|
||||
cy.get('input[name="email"]').type('user[0-9]{enter}')
|
||||
cy.findByText(user2)
|
||||
cy.findByText(user1).should('not.exist')
|
||||
cy.findByLabelText('RegExp').click()
|
||||
cy.findByPlaceholderText('Search users by email or id…').type(
|
||||
'user[0-9]{enter}'
|
||||
)
|
||||
cy.findByRole('link', { name: user2 })
|
||||
cy.findByRole('link', { name: user1 }).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -213,10 +215,12 @@ describe('admin panel', function () {
|
||||
beforeEach(() => {
|
||||
login(admin)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Admin').click()
|
||||
cy.get('nav').findByText('Manage Users').click()
|
||||
cy.get('input[name="email"]').type(user1 + '{enter}')
|
||||
cy.findByText(user1).click()
|
||||
cy.findByRole('menuitem', { name: 'Admin' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Manage Users' }).click()
|
||||
cy.findByPlaceholderText('Search users by email or id…').type(
|
||||
user1 + '{enter}'
|
||||
)
|
||||
cy.findByRole('link', { name: user1 }).click()
|
||||
cy.url().should('match', /\/admin\/user\/[a-fA-F0-9]{24}/)
|
||||
})
|
||||
|
||||
@@ -228,15 +232,15 @@ describe('admin panel', function () {
|
||||
'Audit Log',
|
||||
'Sessions',
|
||||
]
|
||||
cy.get('[role="tab"]').each((el, index) => {
|
||||
cy.wrap(el).findByText(tabs[index]).click()
|
||||
cy.findAllByRole('tab').should('have.length', tabs.length)
|
||||
tabs.forEach(tabName => {
|
||||
cy.findByRole('tab', { name: tabName }).click()
|
||||
})
|
||||
cy.get('[role="tab"]').should('have.length', tabs.length)
|
||||
})
|
||||
|
||||
describe('user info tab', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[role="tab"]').contains('User Info').click()
|
||||
cy.findByRole('tab', { name: 'User Info' }).click()
|
||||
})
|
||||
|
||||
it('displays required sections', () => {
|
||||
@@ -246,33 +250,61 @@ describe('admin panel', function () {
|
||||
})
|
||||
|
||||
it('should not display SaaS-only sections', () => {
|
||||
cy.findByText('Referred User Count').should('not.exist')
|
||||
cy.findByText('Split Test Assignments').should('not.exist')
|
||||
cy.findByText('Experimental Features').should('not.exist')
|
||||
cy.findByText('Service Integration').should('not.exist')
|
||||
cy.findByText('SSO Integrations').should('not.exist')
|
||||
cy.findByText('Security').should('not.exist')
|
||||
cy.findByLabelText('Referred User Count').should('not.exist')
|
||||
cy.findByRole('heading', { name: /Split Test Assignments/ }).should(
|
||||
'not.exist'
|
||||
)
|
||||
cy.findByRole('heading', { name: 'Experimental Features' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
cy.findByRole('heading', { name: 'Service Integration' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
cy.findByRole('heading', { name: 'SSO Integrations' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
cy.findByRole('heading', { name: 'Security' }).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('transfer project ownership', () => {
|
||||
cy.log("access project admin through owners' project list")
|
||||
cy.get('[role="tab"]').contains('Projects').click()
|
||||
cy.get(`a[href="/admin/project/${testProjectId}"]`).click()
|
||||
cy.findByRole('tablist').within(() => {
|
||||
cy.findByRole('tab', { name: 'Projects' }).click()
|
||||
})
|
||||
cy.get(`a[href="/admin/project/${testProjectId}"]`)
|
||||
.should('contain.text', 'Project information')
|
||||
.click()
|
||||
|
||||
cy.findByText('Transfer Ownership').click()
|
||||
cy.get('button[type="submit"]').should('be.disabled')
|
||||
cy.get('input[name="user_id"]').type(user2)
|
||||
cy.get('button[type="submit"]').should('not.be.disabled')
|
||||
cy.get('button[type="submit"]').click()
|
||||
cy.findByText('Transfer project to this user?')
|
||||
cy.get('button').contains('Confirm').click()
|
||||
cy.findByRole('button', { name: 'Transfer Ownership' }).click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('heading', { name: 'Transfer Ownership of Project' })
|
||||
cy.findByRole('button', { name: 'Find' }).should('be.disabled')
|
||||
cy.findByRole('button', { name: 'Confirm' }).should('be.disabled')
|
||||
cy.findByPlaceholderText('User ID or Email').type(user2)
|
||||
cy.findByRole('button', { name: 'Find' }).should('not.be.disabled')
|
||||
cy.findByRole('button', { name: 'Find' }).click()
|
||||
cy.findByText('Transfer project to this user?')
|
||||
cy.findByRole('cell', { name: 'ID' })
|
||||
cy.findByRole('cell', { name: 'Name' })
|
||||
cy.findByRole('cell', { name: 'Email' })
|
||||
cy.findByRole('cell', { name: user2 })
|
||||
cy.findByRole('button', { name: 'Confirm' }).should('not.be.disabled')
|
||||
cy.findByRole('button', { name: 'Confirm' }).click()
|
||||
})
|
||||
|
||||
cy.log('check the project is displayed in the new owner projects tab')
|
||||
cy.get('input[name="email"]').type(user2 + '{enter}')
|
||||
cy.findByText(user2).click()
|
||||
cy.get('[role="tab"]').contains('Projects').click()
|
||||
cy.get(`a[href="/admin/project/${testProjectId}"]`)
|
||||
cy.findByPlaceholderText('Search users by email or id…').type(
|
||||
user2 + '{enter}'
|
||||
)
|
||||
cy.findByRole('link', { name: user2 }).click()
|
||||
cy.findByRole('tablist').within(() => {
|
||||
cy.findByRole('tab', { name: 'Projects' }).click()
|
||||
})
|
||||
cy.get(`a[href="/admin/project/${testProjectId}"]`).should(
|
||||
'contain.text',
|
||||
'Project information'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -284,10 +316,10 @@ describe('admin panel', function () {
|
||||
|
||||
it('displays expected tabs', () => {
|
||||
const tabs = ['Project Info', 'Deleted Docs', 'Audit Log']
|
||||
cy.get('[role="tab"]').each((el, index) => {
|
||||
cy.wrap(el).findByText(tabs[index]).click()
|
||||
cy.findAllByRole('tab').should('have.length', tabs.length)
|
||||
tabs.forEach(tabName => {
|
||||
cy.findByRole('tab', { name: tabName }).click()
|
||||
})
|
||||
cy.get('[role="tab"]').should('have.length', tabs.length)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -297,46 +329,54 @@ describe('admin panel', function () {
|
||||
|
||||
cy.log('select project to delete')
|
||||
findProjectRow(deletedProjectName).within(() =>
|
||||
cy.get('input[type="checkbox"]').first().check()
|
||||
cy
|
||||
.findByRole('checkbox', { name: `Select ${deletedProjectName}` })
|
||||
.first()
|
||||
.check()
|
||||
)
|
||||
|
||||
cy.log('delete project')
|
||||
findProjectRow(deletedProjectName).within(() =>
|
||||
cy.findByRole('button', { name: 'Trash' }).click()
|
||||
)
|
||||
cy.get('button').contains('Confirm').click()
|
||||
cy.findByText(deletedProjectName).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Confirm' }).click()
|
||||
cy.findByRole('link', { name: deletedProjectName }).should('not.exist')
|
||||
|
||||
cy.log('navigate to thrashed projects and delete the project')
|
||||
cy.get('.project-list-sidebar-scroll').within(() => {
|
||||
cy.findByText('Trashed projects').click()
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project categories and tags',
|
||||
})
|
||||
.findByRole('button', { name: 'Trashed projects' })
|
||||
.click()
|
||||
findProjectRow(deletedProjectName).within(() =>
|
||||
cy.findByRole('button', { name: 'Delete' }).click()
|
||||
)
|
||||
cy.get('button').contains('Confirm').click()
|
||||
cy.findByText(deletedProjectName).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Confirm' }).click()
|
||||
cy.findByRole('link', { name: deletedProjectName }).should('not.exist')
|
||||
|
||||
cy.log('login as an admin and navigate to the deleted project')
|
||||
login(admin)
|
||||
cy.visit('/admin/user')
|
||||
cy.get('input[name="email"]').type(user1 + '{enter}')
|
||||
cy.get('a').contains(user1).click()
|
||||
cy.findByText('Deleted Projects').click()
|
||||
cy.get('a').contains(deletedProjectName).click()
|
||||
cy.findByPlaceholderText('Search users by email or id…').type(
|
||||
user1 + '{enter}'
|
||||
)
|
||||
cy.findByRole('link', { name: user1 }).click()
|
||||
cy.findByRole('tab', { name: 'Deleted Projects' }).click()
|
||||
cy.findByRole('link', { name: deletedProjectName }).click()
|
||||
|
||||
cy.log('undelete the project')
|
||||
cy.findByText('Undelete').click()
|
||||
cy.findByText('Undelete').should('not.exist')
|
||||
cy.findByRole('button', { name: 'Undelete' }).click()
|
||||
cy.findByRole('button', { name: 'Undelete' }).should('not.exist')
|
||||
cy.url().should('contain', `/admin/project/${projectToDeleteId}`)
|
||||
|
||||
cy.log('login as the user and verify the project is restored')
|
||||
login(user1)
|
||||
cy.visit('/project')
|
||||
cy.get('.project-list-sidebar-scroll').within(() => {
|
||||
cy.findByText('Trashed projects').click()
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project categories and tags',
|
||||
})
|
||||
cy.findByText(`${deletedProjectName} (Restored)`)
|
||||
.findByRole('button', { name: 'Trashed projects' })
|
||||
.click()
|
||||
cy.findByRole('link', { name: `${deletedProjectName} (Restored)` })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,46 +6,59 @@ import {
|
||||
import { isExcludedBySharding, startWith } from './helpers/config'
|
||||
import { throttledRecompile } from './helpers/compile'
|
||||
|
||||
const USER = 'user@example.com'
|
||||
const COLLABORATOR = 'collaborator@example.com'
|
||||
|
||||
describe('Project creation and compilation', function () {
|
||||
if (isExcludedBySharding('CE_DEFAULT')) return
|
||||
startWith({})
|
||||
ensureUserExists({ email: 'user@example.com' })
|
||||
ensureUserExists({ email: 'collaborator@example.com' })
|
||||
ensureUserExists({ email: USER })
|
||||
ensureUserExists({ email: COLLABORATOR })
|
||||
|
||||
it('users can create project and compile it', function () {
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
createProject('test-project')
|
||||
const recompile = throttledRecompile()
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n\\section{{}Test Section}')
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n\\section{{}Test Section}')
|
||||
})
|
||||
recompile()
|
||||
cy.get('.pdf-viewer').should('contain.text', 'Test Section')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).within(() => {
|
||||
cy.findByLabelText(/Page.*1/i).should('be.visible')
|
||||
cy.findByText('Test Section').should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
it('create and edit markdown file', function () {
|
||||
const fileName = `test-${Date.now()}.md`
|
||||
const markdownContent = '# Markdown title'
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
createProject('test-project')
|
||||
|
||||
// FIXME: Add aria-label maybe? or at least data-test-id
|
||||
cy.findByText('New file').click({ force: true })
|
||||
cy.findByRole('navigation', { name: 'Project files and outline' })
|
||||
.findByRole('button', { name: 'New file' })
|
||||
.click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.get('input').clear()
|
||||
cy.get('input').type(fileName)
|
||||
cy.findByText('Create').click()
|
||||
cy.findByLabelText('File Name').clear().type(fileName)
|
||||
cy.findByRole('button', { name: 'Create' }).click()
|
||||
})
|
||||
cy.findByText(fileName).click()
|
||||
cy.findByRole('button', { name: fileName }).click()
|
||||
// wait until we've switched to the newly created empty file
|
||||
cy.get('.cm-line').should('have.length', 1)
|
||||
cy.get('.cm-line').type(markdownContent)
|
||||
cy.findByText('main.tex').click()
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'have.length',
|
||||
1
|
||||
)
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).type(
|
||||
markdownContent
|
||||
)
|
||||
cy.findByRole('button', { name: 'main.tex' }).click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\maketitle'
|
||||
)
|
||||
cy.findByText(fileName).click()
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('button', { name: fileName }).click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
markdownContent
|
||||
)
|
||||
@@ -54,7 +67,7 @@ describe('Project creation and compilation', function () {
|
||||
it('can link and display linked image from other project', function () {
|
||||
const sourceProjectName = `test-project-${Date.now()}`
|
||||
const targetProjectName = `${sourceProjectName}-target`
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
|
||||
createProject(sourceProjectName, {
|
||||
type: 'Example project',
|
||||
@@ -63,15 +76,17 @@ describe('Project creation and compilation', function () {
|
||||
createProject(targetProjectName)
|
||||
|
||||
// link the image from `projectName` into this project
|
||||
cy.findByText('New file').click({ force: true })
|
||||
cy.findByRole('button', { name: 'New file' }).click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByText('From another project').click()
|
||||
cy.findByRole('button', { name: 'From another project' }).click()
|
||||
cy.findByLabelText('Select a Project').select(sourceProjectName)
|
||||
cy.findByLabelText('Select a File').select('frog.jpg')
|
||||
cy.findByText('Create').click()
|
||||
cy.findByRole('button', { name: 'Create' }).click()
|
||||
})
|
||||
cy.findByTestId('file-tree').findByText('frog.jpg').click()
|
||||
cy.findByText('Another project')
|
||||
cy.findByRole('navigation', { name: 'Project files and outline' })
|
||||
.findByRole('treeitem', { name: 'frog.jpg' })
|
||||
.click()
|
||||
cy.findByRole('link', { name: 'Another project' })
|
||||
.should('have.attr', 'href')
|
||||
.then(href => {
|
||||
cy.get('@sourceProjectId').then(sourceProjectId => {
|
||||
@@ -83,7 +98,7 @@ describe('Project creation and compilation', function () {
|
||||
it('can refresh linked files as collaborator', function () {
|
||||
const sourceProjectName = `test-project-${Date.now()}`
|
||||
const targetProjectName = `${sourceProjectName}-target`
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
createProject(sourceProjectName, {
|
||||
type: 'Example project',
|
||||
open: false,
|
||||
@@ -91,31 +106,36 @@ describe('Project creation and compilation', function () {
|
||||
createProject(targetProjectName).as('targetProjectId')
|
||||
|
||||
// link the image from `projectName` into this project
|
||||
cy.findByText('New file').click({ force: true })
|
||||
cy.findByRole('navigation', { name: 'Project files and outline' })
|
||||
.findByRole('button', { name: 'New file' })
|
||||
.click()
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByText('From another project').click()
|
||||
cy.findByRole('button', { name: 'From another project' }).click()
|
||||
cy.findByLabelText('Select a Project').select(sourceProjectName)
|
||||
cy.findByLabelText('Select a File').select('frog.jpg')
|
||||
cy.findByText('Create').click()
|
||||
cy.findByRole('button', { name: 'Create' }).click()
|
||||
})
|
||||
|
||||
cy.findByText('Share').click()
|
||||
cy.findByRole('navigation', { name: 'Project actions' }).within(() => {
|
||||
cy.findByRole('button', { name: 'Share' }).click()
|
||||
})
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByTestId('collaborator-email-input').type(
|
||||
'collaborator@example.com,'
|
||||
)
|
||||
cy.findByText('Invite').click({ force: true })
|
||||
cy.findByTestId('collaborator-email-input').type(COLLABORATOR + ',')
|
||||
cy.findByRole('button', { name: 'Invite' }).click()
|
||||
cy.findByText('Invite not yet accepted.')
|
||||
})
|
||||
|
||||
login('collaborator@example.com')
|
||||
login(COLLABORATOR)
|
||||
openProjectViaInviteNotification(targetProjectName)
|
||||
cy.get('@targetProjectId').then(targetProjectId => {
|
||||
cy.url().should('include', targetProjectId)
|
||||
})
|
||||
|
||||
cy.findByTestId('file-tree').findByText('frog.jpg').click()
|
||||
cy.findByText('Another project')
|
||||
cy.findByRole('navigation', { name: 'Project files and outline' })
|
||||
.findByRole('treeitem', { name: 'frog.jpg' })
|
||||
.click()
|
||||
cy.findByRole('link', { name: 'Another project' })
|
||||
.should('have.attr', 'href')
|
||||
.then(href => {
|
||||
cy.get('@sourceProjectId').then(sourceProjectId => {
|
||||
|
||||
@@ -10,11 +10,14 @@ import { v4 as uuid } from 'uuid'
|
||||
import { beforeWithReRunOnTestRetry } from './helpers/beforeWithReRunOnTestRetry'
|
||||
import { prepareWaitForNextCompileSlot } from './helpers/compile'
|
||||
|
||||
const USER = 'user@example.com'
|
||||
const COLLABORATOR = 'collaborator@example.com'
|
||||
|
||||
describe('editor', () => {
|
||||
if (isExcludedBySharding('PRO_DEFAULT_1')) return
|
||||
startWith({ pro: true })
|
||||
ensureUserExists({ email: 'user@example.com' })
|
||||
ensureUserExists({ email: 'collaborator@example.com' })
|
||||
ensureUserExists({ email: USER })
|
||||
ensureUserExists({ email: COLLABORATOR })
|
||||
|
||||
let projectName: string
|
||||
let projectId: string
|
||||
@@ -22,7 +25,7 @@ describe('editor', () => {
|
||||
let waitForCompileRateLimitCoolOff: (fn: () => void) => void
|
||||
beforeWithReRunOnTestRetry(function () {
|
||||
projectName = `project-${uuid()}`
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
createProject(projectName, { type: 'Example project', open: false }).then(
|
||||
id => (projectId = id)
|
||||
)
|
||||
@@ -31,7 +34,7 @@ describe('editor', () => {
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
waitForCompileRateLimitCoolOff(() => {
|
||||
openProjectById(projectId)
|
||||
})
|
||||
@@ -40,9 +43,16 @@ describe('editor', () => {
|
||||
describe('spelling', function () {
|
||||
function changeSpellCheckLanguageTo(lng: string) {
|
||||
cy.log(`change project language to '${lng}'`)
|
||||
cy.get('button').contains('Menu').click()
|
||||
cy.get('select[id=settings-menu-spellCheckLanguage]').select(lng)
|
||||
cy.get('[id="left-menu"]').type('{esc}') // close left menu
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByLabelText('Spell check').select(lng)
|
||||
})
|
||||
cy.get('body').type('{esc}')
|
||||
}
|
||||
|
||||
afterEach(function () {
|
||||
@@ -70,20 +80,28 @@ describe('editor', () => {
|
||||
cy.findByText(word).should('not.have.class', 'ol-cm-spelling-error')
|
||||
|
||||
cy.log('remove word from dictionary')
|
||||
cy.get('button').contains('Menu').click()
|
||||
cy.get('button#dictionary-settings').contains('Edit').click()
|
||||
cy.get('[id="dictionary-modal"]').within(() => {
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByLabelText('Dictionary').click()
|
||||
})
|
||||
cy.findByTestId('dictionary-modal').within(() => {
|
||||
cy.findByText(word)
|
||||
.parent()
|
||||
.within(() => cy.get('button').click())
|
||||
.within(() =>
|
||||
cy.findByRole('button', { name: 'Remove from dictionary' }).click()
|
||||
)
|
||||
|
||||
// the modal has 2 close buttons, this ensures the one with the visible label is
|
||||
// clicked, otherwise it would need `force: true`
|
||||
cy.get('.btn').contains('Close').click()
|
||||
cy.contains('button', /close/i).click()
|
||||
})
|
||||
|
||||
cy.log('close left panel')
|
||||
cy.get('[id="left-menu"]').type('{esc}')
|
||||
cy.findByTestId('left-menu').type('{esc}')
|
||||
|
||||
cy.log('rewrite word to force spelling error')
|
||||
cy.get('.cm-line').type('{selectAll}{del}' + word + '{enter}')
|
||||
@@ -94,7 +112,11 @@ describe('editor', () => {
|
||||
|
||||
describe('editor', () => {
|
||||
it('renders jpg', () => {
|
||||
cy.findByTestId('file-tree').findByText('frog.jpg').click()
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project files and outline',
|
||||
})
|
||||
.findByRole('treeitem', { name: 'frog.jpg' })
|
||||
.click()
|
||||
cy.get('[alt="frog.jpg"]')
|
||||
.should('be.visible')
|
||||
.and('have.prop', 'naturalWidth')
|
||||
@@ -108,7 +130,7 @@ describe('editor', () => {
|
||||
force: true,
|
||||
})
|
||||
cy.get('button').contains('𝜉').click()
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\xi'
|
||||
)
|
||||
@@ -120,23 +142,27 @@ describe('editor', () => {
|
||||
|
||||
describe('add new file to project', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('button').contains('New file').click({ force: true })
|
||||
cy.findByRole('button', { name: 'New file' }).click()
|
||||
})
|
||||
|
||||
testNewFileUpload()
|
||||
|
||||
it('should not display import from URL', () => {
|
||||
cy.findByText('From external URL').should('not.exist')
|
||||
cy.findByRole('button', { name: 'From external URL' }).should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('left menu', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('button').contains('Menu').click()
|
||||
cy.findByRole('navigation', {
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
})
|
||||
|
||||
it('can download project sources', () => {
|
||||
cy.get('a').contains('Source').click()
|
||||
cy.findByRole('link', { name: 'Source' }).click()
|
||||
const zipName = projectName.replaceAll('-', '_')
|
||||
cy.task('readFileInZip', {
|
||||
pathToZip: `cypress/downloads/${zipName}.zip`,
|
||||
@@ -146,10 +172,12 @@ describe('editor', () => {
|
||||
|
||||
it('can download project PDF', () => {
|
||||
cy.log('ensure project is compiled')
|
||||
cy.get('.pdf-viewer').should('contain.text', 'Your Paper')
|
||||
|
||||
cy.get('.nav-downloads').within(() => {
|
||||
cy.findByText('PDF').click()
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'contain.text',
|
||||
'Your Paper'
|
||||
)
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('link', { name: 'PDF' }).click()
|
||||
const pdfName = projectName.replaceAll('-', '_')
|
||||
cy.task('readPdf', `cypress/downloads/${pdfName}.pdf`).should(
|
||||
'contain',
|
||||
@@ -160,11 +188,13 @@ describe('editor', () => {
|
||||
|
||||
it('word count', () => {
|
||||
cy.log('ensure project is compiled')
|
||||
cy.get('.pdf-viewer').should('contain.text', 'Your Paper')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'contain.text',
|
||||
'Your Paper'
|
||||
)
|
||||
cy.findByRole('button', { name: 'Word Count' }).click()
|
||||
|
||||
cy.findByText('Word Count').click()
|
||||
|
||||
cy.get('#word-count-modal').within(() => {
|
||||
cy.findByTestId('word-count-modal').within(() => {
|
||||
cy.findByText('Total Words:')
|
||||
cy.findByText('607')
|
||||
cy.findByText('Headers:')
|
||||
@@ -179,51 +209,73 @@ describe('editor', () => {
|
||||
|
||||
describe('layout selector', () => {
|
||||
it('show editor only and switch between editor and pdf', () => {
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
|
||||
cy.findByText('Layout').click()
|
||||
cy.findByText('Editor only').click()
|
||||
cy.findByRole('button', { name: 'Layout' }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', { name: /Editor only/ }).click()
|
||||
})
|
||||
|
||||
cy.get('.pdf-viewer').should('not.be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'not.be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
|
||||
cy.findByText('Switch to PDF').click()
|
||||
cy.findByRole('button', { name: 'Switch to PDF' }).click()
|
||||
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('not.be.visible')
|
||||
|
||||
cy.findByText('Switch to editor').click()
|
||||
cy.findByRole('button', { name: 'Switch to editor' }).click()
|
||||
|
||||
cy.get('.pdf-viewer').should('not.be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'not.be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
})
|
||||
|
||||
it('show PDF only and go back to Editor & PDF', () => {
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
|
||||
cy.findByText('Layout').click()
|
||||
cy.findByText('PDF only').click()
|
||||
cy.findByRole('button', { name: 'Layout' }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', { name: /PDF only/ }).click()
|
||||
})
|
||||
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('not.be.visible')
|
||||
|
||||
cy.findByText('Layout').click()
|
||||
cy.findByText('Editor & PDF').click()
|
||||
cy.findByRole('button', { name: 'Layout' }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', { name: 'Editor & PDF' }).click()
|
||||
})
|
||||
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'be.visible'
|
||||
)
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
})
|
||||
|
||||
it('PDF in a separate tab (tests editor only)', () => {
|
||||
cy.get('.pdf-viewer').should('be.visible')
|
||||
cy.findByTestId('pdf-viewer').should('be.visible')
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
|
||||
cy.findByText('Layout').click()
|
||||
cy.findByText('PDF in separate tab').click()
|
||||
cy.findByRole('button', { name: 'Layout' }).click()
|
||||
cy.findByRole('menu').within(() => {
|
||||
cy.findByRole('menuitem', { name: 'PDF in separate tab' }).click()
|
||||
})
|
||||
|
||||
cy.get('.pdf-viewer').should('not.exist')
|
||||
cy.findByTestId('pdf-viewer').should('not.exist')
|
||||
cy.get('.cm-editor').should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -106,7 +106,7 @@ describe('filestore migration', function () {
|
||||
name: /Create First Project|New Project/,
|
||||
}).click()
|
||||
cy.findByRole('link', { name: 'Example Project' }).click()
|
||||
cy.findByLabelText(/Project name/i).type(projectName)
|
||||
cy.findByLabelText('Project name').type(projectName)
|
||||
cy.findByRole('button', { name: 'Create' }).click()
|
||||
cy.url()
|
||||
.should('match', /\/project\/[a-fA-F0-9]{24}/)
|
||||
|
||||
@@ -14,6 +14,8 @@ import http from 'isomorphic-git/http/web'
|
||||
import LightningFS from '@isomorphic-git/lightning-fs'
|
||||
import { throttledRecompile } from './helpers/compile'
|
||||
|
||||
const USER = 'user@example.com'
|
||||
|
||||
describe('git-bridge', function () {
|
||||
const ENABLED_VARS = {
|
||||
GIT_BRIDGE_ENABLED: 'true',
|
||||
@@ -35,18 +37,21 @@ describe('git-bridge', function () {
|
||||
pro: true,
|
||||
vars: ENABLED_VARS,
|
||||
})
|
||||
ensureUserExists({ email: 'user@example.com' })
|
||||
ensureUserExists({ email: USER })
|
||||
|
||||
function clearAllTokens() {
|
||||
cy.get('button.linking-git-bridge-revoke-button').each(el => {
|
||||
cy.wrap(el).click()
|
||||
cy.findByText('Delete token').click()
|
||||
})
|
||||
cy.findAllByRole('button', { name: 'Remove' })
|
||||
.not('[disabled]')
|
||||
.each($button => {
|
||||
cy.wrap($button).click()
|
||||
cy.findByRole('button', { name: 'Delete token' }).click()
|
||||
})
|
||||
cy.findByRole('dialog').should('not.exist')
|
||||
}
|
||||
|
||||
function maybeClearAllTokens() {
|
||||
cy.visit('/user/settings')
|
||||
cy.findByText('Git integration')
|
||||
cy.findByRole('heading', { name: 'Git integration' })
|
||||
cy.get('button')
|
||||
.contains(/Generate token|Add another token/)
|
||||
.then(btn => {
|
||||
@@ -57,66 +62,83 @@ describe('git-bridge', function () {
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
})
|
||||
|
||||
it('should render the git-bridge UI in the settings', () => {
|
||||
maybeClearAllTokens()
|
||||
cy.visit('/user/settings')
|
||||
cy.findByText('Git integration')
|
||||
cy.get('button').contains('Generate token').click()
|
||||
cy.get('code')
|
||||
cy.findByRole('heading', { name: 'Git integration' })
|
||||
cy.findByRole('button', {
|
||||
name: 'Git integration Generate token',
|
||||
}).click()
|
||||
cy.findByLabelText('Git authentication token')
|
||||
.contains(/olp_[a-zA-Z0-9]{16}/)
|
||||
.then(el => el.text())
|
||||
.as('newToken')
|
||||
cy.findAllByText('Close').last().click()
|
||||
cy.get('@newToken').then(token => {
|
||||
// There can be more than one token with the same prefix when retrying
|
||||
cy.findAllByText(
|
||||
`${token.text().slice(0, 'olp_1234'.length)}${'*'.repeat(12)}`
|
||||
`${token.slice(0, 'olp_1234'.length)}${'*'.repeat(12)}`
|
||||
).should('have.length.at.least', 1)
|
||||
})
|
||||
cy.get('button').contains('Generate token').should('not.exist')
|
||||
cy.get('button').contains('Add another token').should('exist')
|
||||
cy.findByRole('button', {
|
||||
name: 'Git integration Generate token',
|
||||
}).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Add another token' }).should('exist')
|
||||
clearAllTokens()
|
||||
cy.get('button').contains('Generate token').should('exist')
|
||||
cy.get('button').contains('Add another token').should('not.exist')
|
||||
cy.findByRole('button', {
|
||||
name: 'Git integration Generate token',
|
||||
}).should('exist')
|
||||
cy.findByRole('button', { name: 'Add another token' }).should('not.exist')
|
||||
})
|
||||
|
||||
it('should render the git-bridge UI in the editor', function () {
|
||||
maybeClearAllTokens()
|
||||
createProject('git').as('projectId')
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Sync')
|
||||
cy.findByText('Git').click()
|
||||
cy.findByTestId('left-menu').within(() => {
|
||||
cy.findByRole('heading', { name: 'Sync' })
|
||||
cy.findByRole('button', { name: 'Git' }).click()
|
||||
})
|
||||
cy.findByTestId('git-bridge-modal').within(() => {
|
||||
cy.get('@projectId').then(id => {
|
||||
cy.get('code').contains(`git clone ${gitURL(id.toString())}`)
|
||||
cy.findByLabelText('Git clone project command').contains(
|
||||
`git clone ${gitURL(id.toString())}`
|
||||
)
|
||||
})
|
||||
cy.findByRole('button', {
|
||||
name: /generate token/i,
|
||||
name: 'Generate token',
|
||||
}).click()
|
||||
cy.get('code').contains(/olp_[a-zA-Z0-9]{16}/)
|
||||
cy.findByLabelText('Git authentication token').contains(
|
||||
/olp_[a-zA-Z0-9]{16}/
|
||||
)
|
||||
})
|
||||
|
||||
// Re-open
|
||||
cy.url().then(url => cy.visit(url))
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Git').click()
|
||||
cy.findByTestId('left-menu').within(() => {
|
||||
cy.findByRole('button', { name: 'Git' }).click()
|
||||
})
|
||||
cy.findByTestId('git-bridge-modal').within(() => {
|
||||
cy.get('@projectId').then(id => {
|
||||
cy.get('code').contains(`git clone ${gitURL(id.toString())}`)
|
||||
})
|
||||
cy.findByText('Generate token').should('not.exist')
|
||||
cy.findByRole('button', {
|
||||
name: 'Generate token',
|
||||
}).should('not.exist')
|
||||
cy.findByText(/generate a new one in Account settings/)
|
||||
cy.findByText('Go to settings')
|
||||
cy.findByRole('link', { name: 'Go to settings' })
|
||||
.should('have.attr', 'target', '_blank')
|
||||
.and('have.attr', 'href', '/user/settings')
|
||||
})
|
||||
@@ -197,18 +219,23 @@ describe('git-bridge', function () {
|
||||
const recompile = throttledRecompile()
|
||||
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Sync')
|
||||
cy.findByText('Git').click()
|
||||
cy.findByTestId('left-menu').within(() => {
|
||||
cy.findByRole('heading', { name: 'Sync' })
|
||||
cy.findByRole('button', { name: 'Git' }).click()
|
||||
})
|
||||
cy.get('@projectId').then(projectId => {
|
||||
cy.findByTestId('git-bridge-modal').within(() => {
|
||||
cy.get('code').contains(`git clone ${gitURL(projectId.toString())}`)
|
||||
cy.findByLabelText('Git clone project command').contains(
|
||||
`git clone ${gitURL(projectId.toString())}`
|
||||
)
|
||||
})
|
||||
cy.findByRole('heading', { name: 'Clone with Git' })
|
||||
cy.findByRole('button', {
|
||||
name: /generate token/i,
|
||||
name: 'Generate token',
|
||||
}).click()
|
||||
cy.get('code')
|
||||
.contains(/olp_[a-zA-Z0-9]{16}/)
|
||||
@@ -255,8 +282,8 @@ describe('git-bridge', function () {
|
||||
},
|
||||
}
|
||||
const authorOptions = {
|
||||
author: { name: 'user', email: 'user@example.com' },
|
||||
committer: { name: 'user', email: 'user@example.com' },
|
||||
author: { name: 'user', email: USER },
|
||||
committer: { name: 'user', email: USER },
|
||||
}
|
||||
const mainTex = `${dir}/main.tex`
|
||||
|
||||
@@ -372,24 +399,26 @@ Hello world
|
||||
})
|
||||
|
||||
function checkDisabled() {
|
||||
ensureUserExists({ email: 'user@example.com' })
|
||||
ensureUserExists({ email: USER })
|
||||
|
||||
it('should not render the git-bridge UI in the settings', () => {
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
cy.visit('/user/settings')
|
||||
cy.findByText('Git integration').should('not.exist')
|
||||
cy.findByRole('heading', { name: 'Git integration' }).should('not.exist')
|
||||
})
|
||||
it('should not render the git-bridge UI in the editor', function () {
|
||||
login('user@example.com')
|
||||
login(USER)
|
||||
createProject('maybe git')
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Word Count') // wait for lazy loading
|
||||
cy.findByText('Sync').should('not.exist')
|
||||
cy.findByText('Git').should('not.exist')
|
||||
cy.findByTestId('left-menu').within(() => {
|
||||
cy.findByRole('button', { name: 'Word Count' }) // wait for lazy loading
|
||||
cy.findByRole('heading', { name: 'Sync' }).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Git' }).should('not.exist')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export function prepareWaitForNextCompileSlot() {
|
||||
queueReset()
|
||||
triggerCompile()
|
||||
cy.log('Wait for compile to finish')
|
||||
cy.findByText('Recompile').should('be.visible')
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('be.visible')
|
||||
})
|
||||
}
|
||||
function recompile() {
|
||||
|
||||
@@ -2,11 +2,13 @@ import { login } from './login'
|
||||
import { openEmail } from './email'
|
||||
import { v4 as uuid } from 'uuid'
|
||||
|
||||
export const NEW_PROJECT_BUTTON_MATCHER = /new project/i
|
||||
|
||||
export function createProject(
|
||||
name: string,
|
||||
{
|
||||
type = 'Blank project',
|
||||
newProjectButtonMatcher = /new project/i,
|
||||
newProjectButtonMatcher = NEW_PROJECT_BUTTON_MATCHER,
|
||||
open = true,
|
||||
}: {
|
||||
type?: 'Blank project' | 'Example project'
|
||||
@@ -41,7 +43,7 @@ export function createProject(
|
||||
cy.findAllByText(type, { exact: false }).first().click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.get('input').type(name)
|
||||
cy.findByText('Create').click()
|
||||
cy.findByRole('button', { name: 'Create' }).click()
|
||||
})
|
||||
if (open) {
|
||||
cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
|
||||
@@ -104,7 +106,7 @@ function shareProjectByEmail(
|
||||
level: 'Viewer' | 'Editor'
|
||||
) {
|
||||
openProjectByName(projectName)
|
||||
cy.findByText('Share').click()
|
||||
cy.findByRole('button', { name: 'Share' }).click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByLabelText('Add email address', { selector: 'input' }).type(
|
||||
`${email},`
|
||||
@@ -115,10 +117,10 @@ function shareProjectByEmail(
|
||||
cy.findByTestId('add-collaborator-select')
|
||||
.click()
|
||||
.then(() => {
|
||||
cy.findByText(level).click()
|
||||
cy.findByRole('option', { name: level }).click()
|
||||
})
|
||||
})
|
||||
cy.findByText('Invite').click({ force: true })
|
||||
cy.findByRole('button', { name: 'Invite' }).click()
|
||||
cy.findByText('Invite not yet accepted.')
|
||||
})
|
||||
}
|
||||
@@ -203,7 +205,9 @@ export function waitForMainDocToLoad() {
|
||||
|
||||
export function openFile(fileName: string, waitFor: string) {
|
||||
// force: The file-tree pane is too narrow to display the full name.
|
||||
cy.findByTestId('file-tree').findByText(fileName).click({ force: true })
|
||||
cy.findByRole('navigation', { name: 'Project files and outline' })
|
||||
.findByRole('treeitem', { name: fileName })
|
||||
.click({ force: true })
|
||||
|
||||
// wait until we've switched to the selected file
|
||||
cy.findByText('Loading…').should('not.exist')
|
||||
@@ -221,7 +225,9 @@ export function createNewFile() {
|
||||
cy.findByText('Create').click()
|
||||
})
|
||||
// force: The file-tree pane is too narrow to display the full name.
|
||||
cy.findByTestId('file-tree').findByText(fileName).click({ force: true })
|
||||
cy.findByTestId('file-tree')
|
||||
.findByRole('treeitem', { name: fileName })
|
||||
.click({ force: true })
|
||||
|
||||
// wait until we've switched to the newly created empty file
|
||||
cy.findByText('Loading…').should('not.exist')
|
||||
|
||||
@@ -13,29 +13,49 @@ describe('History', function () {
|
||||
|
||||
function addLabel(name: string) {
|
||||
cy.log(`add label ${JSON.stringify(name)}`)
|
||||
cy.findByText('Labels').click()
|
||||
cy.findAllByTestId('history-version-details')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.get('button').click() // TODO: add test-id or aria-label
|
||||
cy.findByText('Label this version').click()
|
||||
// The input is not clickable due to being visually hidden, click its label instead
|
||||
cy.findByRole('complementary', {
|
||||
name: 'Project history and labels',
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText('Labels').click()
|
||||
})
|
||||
cy.findByRole('radio', { name: 'Labels' }).should('be.checked')
|
||||
cy.findByRole('radio', { name: 'All history' }).should('not.be.checked')
|
||||
cy.findAllByTestId('history-version-details')
|
||||
.first()
|
||||
.within(() => {
|
||||
cy.findByRole('button', { name: 'More actions' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Label this version' }).click()
|
||||
})
|
||||
})
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByLabelText(/New label name/i)
|
||||
.as('input')
|
||||
.type(`${name}{enter}`)
|
||||
cy.findByLabelText('New label name').type(`${name}{enter}`)
|
||||
})
|
||||
}
|
||||
|
||||
function downloadVersion(name: string) {
|
||||
cy.log(`download version ${JSON.stringify(name)}`)
|
||||
cy.findByText('Labels').click()
|
||||
cy.findByText(name)
|
||||
.closest('[data-testid="history-version-details"]')
|
||||
.within(() => {
|
||||
cy.get('.history-version-dropdown-menu-btn').click()
|
||||
cy.findByText('Download this version').click()
|
||||
// The input is not clickable due to being visually hidden, click its label instead
|
||||
cy.findByRole('complementary', {
|
||||
name: 'Project history and labels',
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText('Labels').click()
|
||||
})
|
||||
cy.findByRole('radio', { name: 'Labels' }).should('be.checked')
|
||||
cy.findByRole('radio', { name: 'All history' }).should('not.be.checked')
|
||||
cy.findByText(name)
|
||||
.closest('[data-testid="history-version-details"]')
|
||||
.within(() => {
|
||||
cy.findByRole('button', { name: 'More actions' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Download this version' }).click()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const CLASS_ADDITION = 'ol-cm-addition-marker'
|
||||
@@ -46,11 +66,13 @@ describe('History', function () {
|
||||
const recompile = throttledRecompile()
|
||||
|
||||
cy.log('add content, including a line that will get removed soon')
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n% added')
|
||||
cy.findByText('\\maketitle').parent().type('\n% to be removed')
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n% added')
|
||||
cy.findByText('\\maketitle').parent().type('\n% to be removed')
|
||||
})
|
||||
recompile()
|
||||
cy.findByText('History').click()
|
||||
cy.findByRole('button', { name: 'History' }).click()
|
||||
|
||||
cy.log('expect to see additions in history')
|
||||
cy.get('.document-diff-container').within(() => {
|
||||
@@ -61,10 +83,10 @@ describe('History', function () {
|
||||
addLabel('Before removal')
|
||||
|
||||
cy.log('remove content')
|
||||
cy.findByText('Back to editor').click()
|
||||
cy.findByRole('button', { name: 'Back to editor' }).click()
|
||||
cy.findByText('% to be removed').parent().type('{end}{shift}{upArrow}{del}')
|
||||
recompile()
|
||||
cy.findByText('History').click()
|
||||
cy.findByRole('button', { name: 'History' }).click()
|
||||
|
||||
cy.log('expect to see annotation for newly removed content in history')
|
||||
cy.get('.document-diff-container').within(() => {
|
||||
@@ -75,18 +97,32 @@ describe('History', function () {
|
||||
addLabel('After removal')
|
||||
|
||||
cy.log('add more content after labeling')
|
||||
cy.findByText('Back to editor').click()
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n% more')
|
||||
cy.findByRole('button', { name: 'Back to editor' }).click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type('\n% more')
|
||||
})
|
||||
recompile()
|
||||
|
||||
cy.log('compare non current versions')
|
||||
cy.findByText('History').click()
|
||||
cy.findByText('Labels').click()
|
||||
cy.findAllByTestId('compare-icon-version').last().click()
|
||||
cy.findAllByTestId('compare-icon-version').filter(':visible').click()
|
||||
cy.findByText('Compare up to this version').click()
|
||||
|
||||
cy.findByRole('button', { name: 'History' }).click()
|
||||
// The input is not clickable due to being visually hidden, click its label instead
|
||||
cy.findByRole('complementary', {
|
||||
name: 'Project history and labels',
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText('Labels').click()
|
||||
})
|
||||
cy.findByRole('radio', { name: 'Labels' }).should('be.checked')
|
||||
cy.findByRole('radio', { name: 'All history' }).should('not.be.checked')
|
||||
cy.findAllByTestId('compare-icon-version').last().click()
|
||||
cy.findAllByTestId('compare-icon-version').filter(':visible').click()
|
||||
cy.findByRole('menuitem', {
|
||||
name: 'Compare up to this version',
|
||||
}).click()
|
||||
})
|
||||
cy.log(
|
||||
'expect to see annotation for removed content between the two versions'
|
||||
)
|
||||
|
||||
@@ -27,40 +27,49 @@ describe('LearnWiki', function () {
|
||||
it('should add a documentation entry to the nav bar', () => {
|
||||
login(REGULAR_USER)
|
||||
cy.visit('/project')
|
||||
cy.get('nav').findByText('Documentation')
|
||||
cy.findByRole('menuitem', { name: 'Documentation' }).should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'/learn'
|
||||
)
|
||||
})
|
||||
|
||||
it('should display a tutorial link in the welcome page', () => {
|
||||
login(WITHOUT_PROJECTS_USER)
|
||||
cy.visit('/project')
|
||||
cy.findByText(LABEL_LEARN_LATEX)
|
||||
cy.findByRole('link', { name: LABEL_LEARN_LATEX })
|
||||
.should('have.attr', 'href', '/learn/latex/Learn_LaTeX_in_30_minutes')
|
||||
.and('have.attr', 'target', '_blank')
|
||||
.within(() => {
|
||||
cy.get('img').should('have.attr', 'src').and('not.be.empty')
|
||||
})
|
||||
})
|
||||
|
||||
it('should render wiki page', () => {
|
||||
login(REGULAR_USER)
|
||||
cy.visit(UPLOADING_A_PROJECT_URL)
|
||||
// Wiki content
|
||||
cy.get('.page').findByText('Uploading a project')
|
||||
cy.get('.page').contains(/how to create an Overleaf project/)
|
||||
cy.get('img[alt="Creating a new project on Overleaf"]')
|
||||
cy.findByRole('heading', { name: 'Uploading a project' })
|
||||
cy.contains(/how to create an Overleaf project/)
|
||||
cy.findByRole('img', { name: 'Creating a new project on Overleaf' })
|
||||
.should('be.visible')
|
||||
.and((el: any) => {
|
||||
expect(el[0].naturalWidth, 'renders image').to.be.greaterThan(0)
|
||||
})
|
||||
// Wiki navigation
|
||||
cy.get('.contents').findByText('Copying a project')
|
||||
cy.findByRole('link', { name: 'Copying a project' }).should('exist')
|
||||
})
|
||||
|
||||
it('should navigate back and forth', function () {
|
||||
login(REGULAR_USER)
|
||||
cy.visit(COPYING_A_PROJECT_URL)
|
||||
cy.get('.page').findByText('Copying a project')
|
||||
cy.get('.contents').findByText('Uploading a project').click()
|
||||
cy.findByRole('heading', { name: 'Copying a project' })
|
||||
cy.findByRole('link', { name: 'Uploading a project' }).click()
|
||||
cy.url().should('contain', UPLOADING_A_PROJECT_URL)
|
||||
cy.get('.page').findByText('Uploading a project')
|
||||
cy.get('.contents').findByText('Copying a project').click()
|
||||
cy.findByRole('heading', { name: 'Uploading a project' })
|
||||
cy.findByRole('link', { name: 'Copying a project' }).click()
|
||||
cy.url().should('contain', COPYING_A_PROJECT_URL)
|
||||
cy.get('.page').findByText('Copying a project')
|
||||
cy.findByRole('heading', { name: 'Copying a project' })
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -21,8 +21,10 @@ describe('Project List', () => {
|
||||
it("'Import from GitHub' is not displayed in the welcome page", () => {
|
||||
login(WITHOUT_PROJECTS_USER)
|
||||
cy.visit('/project')
|
||||
cy.findByText('Create a new project').click()
|
||||
cy.findByText(/Import from GitHub/i).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Create a new project' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Import from GitHub' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -66,42 +68,50 @@ describe('Project List', () => {
|
||||
it('can assign and remove tags to projects', () => {
|
||||
const tagName = uuid().slice(0, 7) // long tag names are truncated in the UI, which affects selectors
|
||||
cy.log('select project')
|
||||
cy.get(`[aria-label="Select ${projectName}"]`).click()
|
||||
cy.findByRole('checkbox', { name: `Select ${projectName}` }).check()
|
||||
|
||||
cy.log('add tag to project')
|
||||
cy.get('button[aria-label="Tags"]').click()
|
||||
cy.findByText('Create new tag').click()
|
||||
cy.get('input[name="new-tag-form-name"]').type(`${tagName}{enter}`)
|
||||
cy.get(`button[aria-label="Select tag ${tagName}"]`) // tag label in project row
|
||||
cy.findByRole('button', { name: 'Tags' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Create new tag' }).click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('heading', { name: 'Create new tag' })
|
||||
cy.findByLabelText('New tag name').type(`${tagName}{enter}`)
|
||||
})
|
||||
cy.findByRole('button', { name: `Select tag ${tagName}` }) // tag label in project row
|
||||
|
||||
cy.log('remove tag')
|
||||
cy.get(`button[aria-label="Remove tag ${tagName}"]`)
|
||||
cy.findByRole('button', { name: `Remove tag ${tagName}` })
|
||||
.first()
|
||||
.click({ force: true })
|
||||
cy.get(`button[aria-label="Select tag ${tagName}"]`).should('not.exist')
|
||||
.click()
|
||||
cy.findByRole('button', { name: `Select tag ${tagName}` }).should(
|
||||
'not.exist'
|
||||
)
|
||||
})
|
||||
|
||||
it('can filter by tag', () => {
|
||||
cy.log('create a separate project to filter')
|
||||
const nonTaggedProjectName = `project-${uuid()}`
|
||||
login(REGULAR_USER)
|
||||
createProject(nonTaggedProjectName, { open: false })
|
||||
|
||||
cy.log('select project')
|
||||
cy.get(`[aria-label="Select ${projectName}"]`).click()
|
||||
cy.findByRole('checkbox', { name: `Select ${projectName}` }).check()
|
||||
|
||||
cy.log('add tag to project')
|
||||
const tagName = uuid().slice(0, 7) // long tag names are truncated in the UI, which affects selectors
|
||||
cy.get('button[aria-label="Tags"]').click()
|
||||
cy.findByText('Create new tag').click()
|
||||
cy.get('input[name="new-tag-form-name"]').type(`${tagName}{enter}`)
|
||||
cy.findByRole('button', { name: 'Tags' }).click()
|
||||
cy.findByRole('menuitem', { name: 'Create new tag' }).click()
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('heading', { name: 'Create new tag' })
|
||||
cy.findByLabelText('New tag name').type(`${tagName}{enter}`)
|
||||
})
|
||||
|
||||
cy.log(
|
||||
'check the non-tagged project is filtered out after clicking the tag'
|
||||
)
|
||||
cy.findByText(nonTaggedProjectName).should('exist')
|
||||
cy.get('button').contains(tagName).click({ force: true })
|
||||
cy.findByText(nonTaggedProjectName).should('not.exist')
|
||||
cy.findByRole('link', { name: nonTaggedProjectName }).should('exist')
|
||||
cy.findByRole('button', { name: `Select tag ${tagName}` }).click()
|
||||
cy.findByRole('link', { name: nonTaggedProjectName }).should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -43,7 +43,7 @@ describe('Project Sharing', function () {
|
||||
createProject(projectName)
|
||||
|
||||
// Add chat message
|
||||
cy.findByText('Chat').click()
|
||||
cy.findByRole('button', { name: 'Chat' }).click()
|
||||
// wait for lazy loading of the chat pane
|
||||
cy.findByText('Send your first message to your collaborators')
|
||||
cy.get(
|
||||
@@ -61,11 +61,11 @@ describe('Project Sharing', function () {
|
||||
|
||||
function expectContentReadOnlyAccess() {
|
||||
cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\maketitle'
|
||||
)
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'have.attr',
|
||||
'contenteditable',
|
||||
'false'
|
||||
@@ -77,12 +77,12 @@ describe('Project Sharing', function () {
|
||||
cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
|
||||
const recompile = throttledRecompile()
|
||||
// wait for the editor to finish loading
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\maketitle'
|
||||
)
|
||||
// the editor should be writable
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'have.attr',
|
||||
'contenteditable',
|
||||
'true'
|
||||
@@ -90,14 +90,20 @@ describe('Project Sharing', function () {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle').parent().type(`\n\\section{{}${section}}`)
|
||||
// should have written
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
`\\section{${section}}`
|
||||
)
|
||||
// check PDF
|
||||
recompile()
|
||||
cy.get('.pdf-viewer').should('contain.text', projectName)
|
||||
cy.get('.pdf-viewer').should('contain.text', section)
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).within(() => {
|
||||
cy.findByLabelText(/Page.*1/i).should('be.visible')
|
||||
cy.findByText(projectName).should('be.visible')
|
||||
})
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).within(() => {
|
||||
cy.findByLabelText(/Page.*1/i).should('be.visible')
|
||||
cy.contains(section)
|
||||
})
|
||||
}
|
||||
|
||||
function expectNoAccess() {
|
||||
@@ -117,7 +123,7 @@ describe('Project Sharing', function () {
|
||||
}
|
||||
|
||||
function expectChatAccess() {
|
||||
cy.findByText('Chat').click()
|
||||
cy.findByRole('button', { name: 'Chat' }).click()
|
||||
cy.findByText('New Chat Message')
|
||||
}
|
||||
|
||||
@@ -132,17 +138,17 @@ describe('Project Sharing', function () {
|
||||
}
|
||||
|
||||
function expectNoChatAccess() {
|
||||
cy.findByText('Layout') // wait for lazy loading
|
||||
cy.findByText('Chat').should('not.exist')
|
||||
cy.findByRole('button', { name: 'Layout' }) // wait for lazy loading
|
||||
cy.findByRole('button', { name: 'Chat' }).should('not.exist')
|
||||
}
|
||||
|
||||
function expectNoHistoryAccess() {
|
||||
cy.findByText('Layout') // wait for lazy loading
|
||||
cy.findByText('History').should('not.exist')
|
||||
cy.findByRole('button', { name: 'Layout' }) // wait for lazy loading
|
||||
cy.findByRole('button', { name: 'History' }).should('not.exist')
|
||||
}
|
||||
|
||||
function expectCommentAccess() {
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\maketitle'
|
||||
)
|
||||
@@ -151,11 +157,11 @@ describe('Project Sharing', function () {
|
||||
|
||||
cy.findByRole('button', { name: 'Add comment' }).should('be.visible')
|
||||
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).click()
|
||||
}
|
||||
|
||||
function expectNoCommentAccess() {
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).should(
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).should(
|
||||
'contain.text',
|
||||
'\\maketitle'
|
||||
)
|
||||
@@ -163,7 +169,7 @@ describe('Project Sharing', function () {
|
||||
cy.findByText('\\maketitle').parent().dblclick()
|
||||
|
||||
cy.findByRole('button', { name: 'Add comment' }).should('not.exist')
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).click()
|
||||
}
|
||||
|
||||
function expectFullReadOnlyAccess() {
|
||||
@@ -200,12 +206,15 @@ describe('Project Sharing', function () {
|
||||
}
|
||||
|
||||
function expectEditAuthoredAs(author: string) {
|
||||
cy.findByText('History').click()
|
||||
cy.findAllByTestId('history-version-metadata-users')
|
||||
.first()
|
||||
.should('contain.text', author) // might have other edits in the same group
|
||||
cy.findByRole('button', { name: 'History' }).click()
|
||||
cy.findByRole('complementary', {
|
||||
name: 'Project history and labels',
|
||||
}).within(() => {
|
||||
cy.findAllByTestId('history-version-metadata-users')
|
||||
.first()
|
||||
.should('contain.text', author) // might have other edits in the same group
|
||||
})
|
||||
}
|
||||
|
||||
describe('via email', function () {
|
||||
const email = 'collaborator-email@example.com'
|
||||
ensureUserExists({ email })
|
||||
|
||||
@@ -30,30 +30,35 @@ describe('SandboxedCompiles', function () {
|
||||
createProject('sandboxed')
|
||||
const recompile = throttledRecompile()
|
||||
cy.log('wait for compile')
|
||||
cy.get('.pdf-viewer').should('contain.text', 'sandboxed')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'contain.text',
|
||||
'sandboxed'
|
||||
)
|
||||
|
||||
cy.log('Check which compiler version was used, expect 2023')
|
||||
cy.get('[aria-label="View logs"]').click()
|
||||
cy.findByRole('button', { name: 'View logs' }).click()
|
||||
cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2023\) /)
|
||||
|
||||
cy.log('Switch TeXLive version from 2023 to 2022')
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText(LABEL_TEX_LIVE_VERSION)
|
||||
.parent()
|
||||
.findByText('2023')
|
||||
.parent()
|
||||
.select('2022')
|
||||
cy.get('.left-menu-modal-backdrop').click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('option', { name: '2023' }).should('be.selected')
|
||||
cy.findByRole('combobox', { name: LABEL_TEX_LIVE_VERSION }).select(
|
||||
'2022'
|
||||
)
|
||||
})
|
||||
cy.get('body').type('{esc}')
|
||||
cy.findByRole('dialog').should('not.exist')
|
||||
|
||||
cy.log('Trigger compile with other TeX Live version')
|
||||
recompile()
|
||||
|
||||
cy.log('Check which compiler version was used, expect 2022')
|
||||
cy.get('[aria-label="View logs"]').click()
|
||||
cy.findByRole('button', { name: 'View logs' }).click()
|
||||
cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2022\) /)
|
||||
})
|
||||
|
||||
@@ -101,39 +106,43 @@ describe('SandboxedCompiles', function () {
|
||||
projectName = `Project ${uuid()}`
|
||||
createProject(projectName)
|
||||
const recompile = throttledRecompile()
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle')
|
||||
.parent()
|
||||
.type(
|
||||
`\n\\pagebreak\n\\section{{}Section A}\n\\pagebreak\n\\section{{}Section B}\n\\pagebreak`
|
||||
)
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(
|
||||
() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle')
|
||||
.parent()
|
||||
.type(
|
||||
`\n\\pagebreak\n\\section{{}Section A}\n\\pagebreak\n\\section{{}Section B}\n\\pagebreak`
|
||||
)
|
||||
}
|
||||
)
|
||||
recompile()
|
||||
cy.log('wait for pdf-rendering')
|
||||
cy.get('.pdf-viewer').within(() => {
|
||||
cy.findByText(projectName)
|
||||
})
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).findByText(
|
||||
projectName
|
||||
)
|
||||
})
|
||||
|
||||
it('should sync to code', function () {
|
||||
cy.log('navigate to \\maketitle using double click in PDF')
|
||||
cy.get('.pdf-viewer').within(() => {
|
||||
cy.findByText(projectName).dblclick()
|
||||
})
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' })
|
||||
.findByText(projectName)
|
||||
.dblclick()
|
||||
cy.get('.cm-activeLine').should('have.text', '\\maketitle')
|
||||
|
||||
cy.log('navigate to Section A using double click in PDF')
|
||||
cy.get('.pdf-viewer').within(() => {
|
||||
cy.findByText('Section A').dblclick()
|
||||
})
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' })
|
||||
.findByText('Section A')
|
||||
.dblclick()
|
||||
cy.get('.cm-activeLine').should('have.text', '\\section{Section A}')
|
||||
|
||||
cy.log('navigate to Section B using arrow button')
|
||||
cy.get('.pdfjs-viewer-inner')
|
||||
cy.findByTestId('pdfjs-viewer-inner')
|
||||
.should('have.prop', 'scrollTop')
|
||||
.as('start')
|
||||
cy.get('.pdf-viewer').within(() => {
|
||||
cy.findByText('Section B').scrollIntoView()
|
||||
})
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' })
|
||||
.findByText('Section B')
|
||||
.scrollIntoView()
|
||||
cy.get('@start').then((start: any) => {
|
||||
waitUntilScrollingFinished('.pdfjs-viewer-inner', start)
|
||||
})
|
||||
@@ -141,21 +150,27 @@ describe('SandboxedCompiles', function () {
|
||||
// Cypress appears to click on a button that references a stale position.
|
||||
// Adding a cy.wait() statement is the most reliable "fix" so far :/
|
||||
cy.wait(1000)
|
||||
cy.get('[aria-label^="Go to PDF location in code"]').click()
|
||||
cy.findByRole('button', {
|
||||
name: 'Go to PDF location in code (Tip: double click on the PDF for best results)',
|
||||
}).click()
|
||||
cy.get('.cm-activeLine').should('have.text', '\\section{Section B}')
|
||||
})
|
||||
|
||||
it('should sync to pdf', function () {
|
||||
cy.log('zoom in')
|
||||
cy.findByText('45%').click()
|
||||
cy.findByText('400%').click()
|
||||
cy.findByRole('button', { name: /^\d+%$/ }).click() // TODO: ARIA label
|
||||
cy.findByRole('menuitem', { name: '400%' }).click()
|
||||
cy.log('scroll to top')
|
||||
cy.get('.pdfjs-viewer-inner').scrollTo('top')
|
||||
cy.findByTestId('pdfjs-viewer-inner').scrollTo('top')
|
||||
waitUntilScrollingFinished('.pdfjs-viewer-inner', -1).as('start')
|
||||
|
||||
cy.log('navigate to title')
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.get('[aria-label="Go to code location in PDF"]').click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(
|
||||
() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
}
|
||||
)
|
||||
cy.findByRole('button', { name: 'Go to code location in PDF' }).click()
|
||||
cy.get('@start').then((start: any) => {
|
||||
waitUntilScrollingFinished('.pdfjs-viewer-inner', start)
|
||||
.as('title')
|
||||
@@ -163,10 +178,10 @@ describe('SandboxedCompiles', function () {
|
||||
})
|
||||
|
||||
cy.log('navigate to Section A')
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).within(
|
||||
() => cy.findByText('Section A').click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() =>
|
||||
cy.findByText('Section A').click()
|
||||
)
|
||||
cy.get('[aria-label="Go to code location in PDF"]').click()
|
||||
cy.findByRole('button', { name: 'Go to code location in PDF' }).click()
|
||||
cy.get('@title').then((title: any) => {
|
||||
waitUntilScrollingFinished('.pdfjs-viewer-inner', title)
|
||||
.as('sectionA')
|
||||
@@ -174,10 +189,10 @@ describe('SandboxedCompiles', function () {
|
||||
})
|
||||
|
||||
cy.log('navigate to Section B')
|
||||
cy.findByRole('textbox', { name: /Source Editor editing/i }).within(
|
||||
() => cy.findByText('Section B').click()
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() =>
|
||||
cy.findByText('Section B').click()
|
||||
)
|
||||
cy.get('[aria-label="Go to code location in PDF"]').click()
|
||||
cy.findByRole('button', { name: 'Go to code location in PDF' }).click()
|
||||
cy.get('@sectionA').then((title: any) => {
|
||||
waitUntilScrollingFinished('.pdfjs-viewer-inner', title)
|
||||
.as('sectionB')
|
||||
@@ -192,14 +207,18 @@ describe('SandboxedCompiles', function () {
|
||||
login('user@example.com')
|
||||
createProject('test-project')
|
||||
const recompile = throttledRecompile()
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle')
|
||||
.parent()
|
||||
.type('\n\\fakeCommand{} \n\\section{{}Test Section}')
|
||||
cy.findByRole('textbox', { name: 'Source Editor editing' }).within(() => {
|
||||
cy.findByText('\\maketitle').parent().click()
|
||||
cy.findByText('\\maketitle')
|
||||
.parent()
|
||||
.type('\n\\fakeCommand{} \n\\section{{}Test Section}')
|
||||
})
|
||||
recompile()
|
||||
recompile()
|
||||
cy.get('.pdf-viewer').should('contain.text', 'Test Section')
|
||||
cy.get('.logs-pane').should('not.contain.text', 'No PDF')
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).within(() => {
|
||||
cy.findByText('Test Section').should('contain.text', 'Test Section')
|
||||
})
|
||||
cy.findByTestId('logs-pane').should('not.contain.text', 'No PDF')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -208,30 +227,32 @@ describe('SandboxedCompiles', function () {
|
||||
createProject('XeLaTeX')
|
||||
const recompile = throttledRecompile()
|
||||
cy.log('wait for compile')
|
||||
cy.get('.pdf-viewer').should('contain.text', 'XeLaTeX')
|
||||
|
||||
cy.findByRole('region', { name: 'PDF preview and logs' }).should(
|
||||
'contain.text',
|
||||
'XeLaTeX'
|
||||
)
|
||||
cy.log('Check which compiler was used, expect pdfLaTeX')
|
||||
cy.get('[aria-label="View logs"]').click()
|
||||
cy.findByRole('button', { name: 'View logs' }).click()
|
||||
cy.findByText(/This is pdfTeX/)
|
||||
|
||||
cy.log('Switch compiler to from pdfLaTeX to XeLaTeX')
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Compiler')
|
||||
.parent()
|
||||
.findByText('pdfLaTeX')
|
||||
.parent()
|
||||
.select('XeLaTeX')
|
||||
cy.get('.left-menu-modal-backdrop').click()
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('option', { name: 'pdfLaTeX' }).should('be.selected')
|
||||
cy.findByRole('combobox', { name: 'Compiler' }).select('XeLaTeX')
|
||||
})
|
||||
cy.get('body').type('{esc}')
|
||||
cy.findByRole('dialog').should('not.exist')
|
||||
|
||||
cy.log('Trigger compile with other compiler')
|
||||
recompile()
|
||||
|
||||
cy.log('Check which compiler was used, expect XeLaTeX')
|
||||
cy.get('[aria-label="View logs"]').click()
|
||||
cy.findByRole('button', { name: 'View logs' }).click()
|
||||
cy.findByText(/This is XeTeX/)
|
||||
})
|
||||
}
|
||||
@@ -252,9 +273,9 @@ describe('SandboxedCompiles', function () {
|
||||
|
||||
cy.log('Check that there is no TeX Live version toggle')
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Word Count') // wait for lazy loading
|
||||
cy.findByText(LABEL_TEX_LIVE_VERSION).should('not.exist')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isExcludedBySharding, startWith } from './helpers/config'
|
||||
import { ensureUserExists, login } from './helpers/login'
|
||||
import { createProject } from './helpers/project'
|
||||
import { createProject, NEW_PROJECT_BUTTON_MATCHER } from './helpers/project'
|
||||
|
||||
const WITHOUT_PROJECTS_USER = 'user-without-projects@example.com'
|
||||
const ADMIN_USER = 'admin@example.com'
|
||||
@@ -43,7 +43,9 @@ describe('Templates', () => {
|
||||
it('should show templates link on welcome page', () => {
|
||||
login(WITHOUT_PROJECTS_USER)
|
||||
cy.visit('/')
|
||||
cy.findByText(LABEL_BROWSE_TEMPLATES).click()
|
||||
cy.findByRole('link', { name: LABEL_BROWSE_TEMPLATES })
|
||||
.should('have.attr', 'href', '/templates')
|
||||
.click()
|
||||
cy.url().should('match', /\/templates$/)
|
||||
})
|
||||
|
||||
@@ -56,9 +58,9 @@ describe('Templates', () => {
|
||||
createProject(name, { type: 'Example project' }).as('templateProjectId')
|
||||
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Manage Template').click()
|
||||
|
||||
@@ -139,9 +141,9 @@ describe('Templates', () => {
|
||||
cy.visit(`/project/${projectId}`)
|
||||
)
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Manage Template').click()
|
||||
cy.findByText('Publish').click()
|
||||
@@ -168,9 +170,9 @@ describe('Templates', () => {
|
||||
cy.url().should('match', /\/project\/[a-f0-9]{24}$/)
|
||||
cy.get('.project-name').should('contain.text', 'Your Paper') // might have (1) suffix
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Word Count') // wait for lazy loading
|
||||
cy.findByText('Manage Template').should('not.exist')
|
||||
@@ -191,9 +193,9 @@ describe('Templates', () => {
|
||||
cy.visit(`/project/${projectId}`)
|
||||
)
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Manage Template').click()
|
||||
cy.findByText('Unpublish')
|
||||
@@ -206,9 +208,9 @@ describe('Templates', () => {
|
||||
cy.visit(`/project/${projectId}`)
|
||||
)
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Manage Template').click()
|
||||
cy.findByText('Unpublish').click()
|
||||
@@ -218,9 +220,7 @@ describe('Templates', () => {
|
||||
|
||||
// check for template links, after creating the first project
|
||||
cy.visit('/')
|
||||
cy.findAllByRole('button')
|
||||
.contains(/new project/i)
|
||||
.click()
|
||||
cy.findAllByRole('button', { name: NEW_PROJECT_BUTTON_MATCHER }).click()
|
||||
cy.findAllByText('All Templates')
|
||||
.first()
|
||||
.parent()
|
||||
@@ -236,9 +236,9 @@ describe('Templates', () => {
|
||||
createProject('maybe templates')
|
||||
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Word Count') // wait for lazy loading
|
||||
cy.findByText('Manage Template').should('not.exist')
|
||||
@@ -250,16 +250,14 @@ describe('Templates', () => {
|
||||
|
||||
// check for template links, after creating the first project
|
||||
cy.visit('/')
|
||||
cy.findAllByRole('button')
|
||||
.contains(/new project/i)
|
||||
.click()
|
||||
cy.findAllByRole('button', { name: NEW_PROJECT_BUTTON_MATCHER }).click()
|
||||
cy.findAllByText('All Templates').should('not.exist')
|
||||
})
|
||||
|
||||
it('should not show templates link on welcome page', () => {
|
||||
login(WITHOUT_PROJECTS_USER)
|
||||
cy.visit('/')
|
||||
cy.findByText(/new project/i) // wait for lazy loading
|
||||
cy.findByText(NEW_PROJECT_BUTTON_MATCHER) // wait for lazy loading
|
||||
cy.findByText(LABEL_BROWSE_TEMPLATES).should('not.exist')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ describe('Upgrading', function () {
|
||||
cy.log('Trigger full flush')
|
||||
recompile()
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project Layout, Sharing, and Submission/i,
|
||||
name: 'Project Layout, Sharing, and Submission',
|
||||
})
|
||||
.findByRole('button', { name: /Menu/i })
|
||||
.findByRole('button', { name: 'Menu' })
|
||||
.click()
|
||||
cy.findByText('Source').click()
|
||||
cy.get('.left-menu-modal-backdrop').click({ force: true })
|
||||
@@ -121,7 +121,7 @@ describe('Upgrading', function () {
|
||||
|
||||
cy.url().should('match', /\/project\/[a-fA-F0-9]{24}/)
|
||||
cy.findByRole('navigation', {
|
||||
name: /Project actions/i,
|
||||
name: 'Project actions',
|
||||
}).within(() => {
|
||||
cy.findByText(PROJECT_NAME)
|
||||
})
|
||||
|
||||
@@ -665,7 +665,7 @@
|
||||
"git_bridge_modal_review_access": "",
|
||||
"git_bridge_modal_see_once": "",
|
||||
"git_bridge_modal_use_previous_token": "",
|
||||
"git_clone_project": "",
|
||||
"git_clone_project_command": "",
|
||||
"git_clone_this_project": "",
|
||||
"git_integration": "",
|
||||
"git_integration_info": "",
|
||||
|
||||
+14
-3
@@ -121,7 +121,9 @@ function ActionButton({
|
||||
titleId,
|
||||
}: ActionButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
const upgradeTextId = `${titleId}-upgrade`
|
||||
const linkTextId = `${titleId}-link`
|
||||
const unlinkTextId = `${titleId}-unlink`
|
||||
|
||||
if (!hasFeature) {
|
||||
return (
|
||||
@@ -129,17 +131,19 @@ function ActionButton({
|
||||
variant="primary"
|
||||
href="/user/subscription/plans"
|
||||
onClick={() => trackUpgradeClick(integration)}
|
||||
aria-labelledby={`${titleId} ${linkTextId}`}
|
||||
aria-labelledby={`${titleId} ${upgradeTextId}`}
|
||||
>
|
||||
<span id={linkTextId}>{t('upgrade')}</span>
|
||||
<span id={upgradeTextId}>{t('upgrade')}</span>
|
||||
</OLButton>
|
||||
)
|
||||
} else if (linked) {
|
||||
return (
|
||||
<OLButton
|
||||
variant="danger-ghost"
|
||||
aria-labelledby={`${unlinkTextId} ${titleId}`}
|
||||
onClick={handleUnlinkClick}
|
||||
disabled={disabled}
|
||||
id={unlinkTextId}
|
||||
>
|
||||
{t('unlink')}
|
||||
</OLButton>
|
||||
@@ -148,7 +152,12 @@ function ActionButton({
|
||||
return (
|
||||
<>
|
||||
{disabled ? (
|
||||
<OLButton disabled variant="secondary">
|
||||
<OLButton
|
||||
disabled
|
||||
variant="secondary"
|
||||
aria-labelledby={`${linkTextId} ${titleId}`}
|
||||
id={linkTextId}
|
||||
>
|
||||
{t('link')}
|
||||
</OLButton>
|
||||
) : (
|
||||
@@ -156,6 +165,8 @@ function ActionButton({
|
||||
variant="secondary"
|
||||
href={linkPath}
|
||||
onClick={() => trackLinkingClick(integration)}
|
||||
aria-labelledby={`${linkTextId} ${titleId}`}
|
||||
id={linkTextId}
|
||||
>
|
||||
{t('link')}
|
||||
</OLButton>
|
||||
|
||||
@@ -868,7 +868,7 @@
|
||||
"git_bridge_modal_review_access": "<0>You have review access to this project.</0> This means you can pull from __appName__ but you can’t push any changes you make back to this project.",
|
||||
"git_bridge_modal_see_once": "You’ll only see this token once. To delete it or generate a new one, visit Account settings. For detailed instructions and troubleshooting, read our <0>help page</0>.",
|
||||
"git_bridge_modal_use_previous_token": "If you’re prompted for a password, you can use a previously generated Git authentication token. Or you can generate a new one in Account settings. For more support, read our <0>help page</0>.",
|
||||
"git_clone_project": "Git clone project",
|
||||
"git_clone_project_command": "Git clone project command",
|
||||
"git_clone_this_project": "Git clone this project.",
|
||||
"git_gitHub_dropbox_mendeley_papers_and_zotero_integrations": "Git, GitHub, Dropbox, Papers, Zotero, and Mendeley integrations",
|
||||
"git_integration": "Git integration",
|
||||
|
||||
@@ -148,7 +148,7 @@ describe('change list', function () {
|
||||
name: /Project history and labels/i,
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: /Show all of the project history/i,
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText(/Labels/i).click()
|
||||
})
|
||||
@@ -353,7 +353,7 @@ describe('change list', function () {
|
||||
name: /Project history and labels/i,
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: /Show all of the project history/i,
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText(/Labels/i).click()
|
||||
})
|
||||
@@ -716,7 +716,7 @@ describe('change list', function () {
|
||||
name: /Project history and labels/i,
|
||||
}).within(() => {
|
||||
cy.findByRole('group', {
|
||||
name: /Show all of the project history/i,
|
||||
name: 'Show all of the project history or only labelled versions.',
|
||||
}).within(() => {
|
||||
cy.findByText(/Labels/i).click()
|
||||
})
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ describe('<AccountInfoSection />', function () {
|
||||
})
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', {
|
||||
name: /update/i,
|
||||
name: 'Update account info',
|
||||
})
|
||||
)
|
||||
expect(updateMock.callHistory.called()).to.be.true
|
||||
@@ -68,7 +68,7 @@ describe('<AccountInfoSection />', function () {
|
||||
target: { value: 'john' },
|
||||
})
|
||||
const button = screen.getByRole('button', {
|
||||
name: /update/i,
|
||||
name: 'Update account info',
|
||||
}) as HTMLButtonElement
|
||||
|
||||
expect(button.disabled).to.be.true
|
||||
|
||||
+68
-69
@@ -63,17 +63,16 @@ function resetFetchMock() {
|
||||
}
|
||||
|
||||
async function confirmCodeForEmail(email: string) {
|
||||
await screen.findByText(
|
||||
`Enter the 6-digit confirmation code sent to ${email}.`
|
||||
)
|
||||
const inputCode = screen.getByLabelText(/6-digit confirmation code/i)
|
||||
const inputCode = await screen.findByRole('textbox', {
|
||||
name: `Enter the 6-digit confirmation code sent to ${email}.`,
|
||||
})
|
||||
fireEvent.change(inputCode, { target: { value: '123456' } })
|
||||
const submitCodeBtn = screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: 'Confirm',
|
||||
})
|
||||
fireEvent.click(submitCodeBtn)
|
||||
await waitForElementToBeRemoved(() =>
|
||||
screen.getByRole('button', { name: /confirming/i })
|
||||
screen.getByRole('button', { name: 'Confirming' })
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ describe('<EmailsSection />', function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
|
||||
await screen.findByRole('button', { name: /add another email/i })
|
||||
await screen.findByRole('button', { name: 'Add another email' })
|
||||
})
|
||||
|
||||
it('renders input', async function () {
|
||||
@@ -105,11 +104,11 @@ describe('<EmailsSection />', function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
fireEvent.click(button)
|
||||
|
||||
await screen.findByLabelText(/email/i, { selector: 'input' })
|
||||
await screen.findByRole('textbox', { name: 'Email' })
|
||||
})
|
||||
|
||||
it('renders "Start adding your address" until a valid email is typed', async function () {
|
||||
@@ -120,17 +119,17 @@ describe('<EmailsSection />', function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
fireEvent.click(button)
|
||||
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
|
||||
// initially the text is displayed and the "add email" button disabled
|
||||
screen.getByText('Start by adding your email address.')
|
||||
expect(
|
||||
screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
}).disabled
|
||||
).to.be.true
|
||||
|
||||
@@ -141,7 +140,7 @@ describe('<EmailsSection />', function () {
|
||||
screen.getByText('Start by adding your email address.')
|
||||
expect(
|
||||
screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
}).disabled
|
||||
).to.be.true
|
||||
|
||||
@@ -152,7 +151,7 @@ describe('<EmailsSection />', function () {
|
||||
expect(screen.queryByText('Start by adding your email address.')).to.be.null
|
||||
expect(
|
||||
screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
}).disabled
|
||||
).to.be.false
|
||||
})
|
||||
@@ -162,11 +161,11 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
fireEvent.click(button)
|
||||
|
||||
screen.getByRole('button', { name: /add new email/i })
|
||||
screen.getByRole('button', { name: 'Add new email' })
|
||||
})
|
||||
|
||||
it('prevent users from adding new emails when the limit is reached', async function () {
|
||||
@@ -182,7 +181,7 @@ describe('<EmailsSection />', function () {
|
||||
'You can have a maximum of 10 email addresses on this account. To add another email address, please delete an existing one.'
|
||||
)
|
||||
|
||||
expect(screen.queryByRole('button', { name: /add another email/i })).to.not
|
||||
expect(screen.queryByRole('button', { name: 'Add another email' })).to.not
|
||||
.exist
|
||||
})
|
||||
|
||||
@@ -192,7 +191,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
|
||||
'button',
|
||||
{ name: /add another email/i }
|
||||
{ name: 'Add another email' }
|
||||
)
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -203,14 +202,14 @@ describe('<EmailsSection />', function () {
|
||||
.post('/user/emails/confirm-secondary', 200)
|
||||
|
||||
fireEvent.click(addAnotherEmailBtn)
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: userEmailData.email },
|
||||
})
|
||||
|
||||
const submitBtn = screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
})
|
||||
|
||||
expect(submitBtn.disabled).to.be.false
|
||||
@@ -221,7 +220,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
await waitForElementToBeRemoved(() =>
|
||||
screen.getByRole('button', {
|
||||
name: /Loading/i,
|
||||
name: 'Loading',
|
||||
})
|
||||
)
|
||||
|
||||
@@ -235,7 +234,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
|
||||
'button',
|
||||
{ name: /add another email/i }
|
||||
{ name: 'Add another email' }
|
||||
)
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -245,14 +244,14 @@ describe('<EmailsSection />', function () {
|
||||
.post('/user/emails/secondary', 400)
|
||||
|
||||
fireEvent.click(addAnotherEmailBtn)
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: userEmailData.email },
|
||||
})
|
||||
|
||||
const submitBtn = screen.getByRole<HTMLButtonElement>('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
})
|
||||
|
||||
expect(submitBtn.disabled).to.be.false
|
||||
@@ -262,7 +261,7 @@ describe('<EmailsSection />', function () {
|
||||
expect(submitBtn.disabled).to.be.true
|
||||
|
||||
await screen.findByText(
|
||||
/Invalid Request. Please correct the data and try again./i
|
||||
'Invalid Request. Please correct the data and try again.'
|
||||
)
|
||||
expect(submitBtn).to.not.be.null
|
||||
expect(submitBtn.disabled).to.be.false
|
||||
@@ -273,7 +272,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -282,7 +281,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
@@ -297,7 +296,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -306,14 +305,14 @@ describe('<EmailsSection />', function () {
|
||||
await userEvent.click(button)
|
||||
|
||||
await userEvent.type(
|
||||
screen.getByLabelText(/email/i, { selector: 'input' }),
|
||||
screen.getByRole('textbox', { name: 'Email' }),
|
||||
userEmailData.email
|
||||
)
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /let us know/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
|
||||
|
||||
const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
|
||||
name: /university/i,
|
||||
name: 'University',
|
||||
})
|
||||
|
||||
expect(universityInput.disabled).to.be.true
|
||||
@@ -330,7 +329,7 @@ describe('<EmailsSection />', function () {
|
||||
// Select the country from dropdown
|
||||
await userEvent.type(
|
||||
screen.getByRole('combobox', {
|
||||
name: /country/i,
|
||||
name: 'Country',
|
||||
}),
|
||||
country
|
||||
)
|
||||
@@ -347,10 +346,10 @@ describe('<EmailsSection />', function () {
|
||||
await screen.findByText(userEmailData.affiliation.institution.name)
|
||||
)
|
||||
|
||||
const roleInput = screen.getByRole('combobox', { name: /role/i })
|
||||
const roleInput = screen.getByRole('combobox', { name: 'Role' })
|
||||
await userEvent.type(roleInput, userEmailData.affiliation.role!)
|
||||
const departmentInput = screen.getByRole('combobox', {
|
||||
name: /department/i,
|
||||
name: 'Department',
|
||||
})
|
||||
await userEvent.click(departmentInput)
|
||||
await userEvent.click(screen.getByText(customDepartment))
|
||||
@@ -370,7 +369,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
await userEvent.click(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
})
|
||||
)
|
||||
|
||||
@@ -402,7 +401,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -422,14 +421,14 @@ describe('<EmailsSection />', function () {
|
||||
// open "add new email" section and click "let us know" to open the Country/University form
|
||||
await userEvent.click(button)
|
||||
await userEvent.type(
|
||||
screen.getByLabelText(/email/i, { selector: 'input' }),
|
||||
screen.getByRole('textbox', { name: 'Email' }),
|
||||
userEmailData.email
|
||||
)
|
||||
await userEvent.click(screen.getByRole('button', { name: /let us know/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
|
||||
|
||||
// select a country
|
||||
const countryInput = screen.getByRole<HTMLInputElement>('combobox', {
|
||||
name: /country/i,
|
||||
name: 'Country',
|
||||
})
|
||||
await userEvent.click(countryInput)
|
||||
await userEvent.type(countryInput, 'Germ')
|
||||
@@ -437,7 +436,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
// match several universities on initial typing
|
||||
const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
|
||||
name: /university/i,
|
||||
name: 'University',
|
||||
})
|
||||
await userEvent.click(universityInput)
|
||||
await userEvent.type(universityInput, 'bo')
|
||||
@@ -458,7 +457,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -467,14 +466,14 @@ describe('<EmailsSection />', function () {
|
||||
await userEvent.click(button)
|
||||
|
||||
await userEvent.type(
|
||||
screen.getByLabelText(/email/i, { selector: 'input' }),
|
||||
screen.getByRole('textbox', { name: 'Email' }),
|
||||
userEmailData.email
|
||||
)
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /let us know/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
|
||||
|
||||
const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
|
||||
name: /university/i,
|
||||
name: 'University',
|
||||
})
|
||||
|
||||
expect(universityInput.disabled).to.be.true
|
||||
@@ -491,7 +490,7 @@ describe('<EmailsSection />', function () {
|
||||
// Select the country from dropdown
|
||||
await userEvent.type(
|
||||
screen.getByRole('combobox', {
|
||||
name: /country/i,
|
||||
name: 'Country',
|
||||
}),
|
||||
country
|
||||
)
|
||||
@@ -505,10 +504,10 @@ describe('<EmailsSection />', function () {
|
||||
// Enter the university manually
|
||||
await userEvent.type(universityInput, newUniversity)
|
||||
|
||||
const roleInput = screen.getByRole('combobox', { name: /role/i })
|
||||
const roleInput = screen.getByRole('combobox', { name: 'Role' })
|
||||
await userEvent.type(roleInput, userEmailData.affiliation.role!)
|
||||
const departmentInput = screen.getByRole('combobox', {
|
||||
name: /department/i,
|
||||
name: 'Department',
|
||||
})
|
||||
await userEvent.type(departmentInput, userEmailData.affiliation.department!)
|
||||
|
||||
@@ -530,7 +529,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
await userEvent.click(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
})
|
||||
)
|
||||
|
||||
@@ -573,7 +572,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -586,7 +585,7 @@ describe('<EmailsSection />', function () {
|
||||
await userEvent.click(button)
|
||||
|
||||
await userEvent.type(
|
||||
screen.getByLabelText(/email/i, { selector: 'input' }),
|
||||
screen.getByRole('textbox', { name: 'Email' }),
|
||||
`user@${hostnameFirstChar}`
|
||||
)
|
||||
|
||||
@@ -596,37 +595,37 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
expect(
|
||||
screen.queryByRole('combobox', {
|
||||
name: /country/i,
|
||||
name: 'Country',
|
||||
})
|
||||
).to.be.null
|
||||
expect(
|
||||
screen.queryByRole('combobox', {
|
||||
name: /university/i,
|
||||
name: 'University',
|
||||
})
|
||||
).to.be.null
|
||||
screen.getByRole('combobox', {
|
||||
name: /role/i,
|
||||
name: 'Role',
|
||||
})
|
||||
screen.getByRole('combobox', {
|
||||
name: /department/i,
|
||||
name: 'Department',
|
||||
})
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /change/i }))
|
||||
await userEvent.click(screen.getByRole('button', { name: 'Change' }))
|
||||
|
||||
screen.getByRole('combobox', {
|
||||
name: /country/i,
|
||||
name: 'Country',
|
||||
})
|
||||
screen.getByRole('combobox', {
|
||||
name: /university/i,
|
||||
name: 'University',
|
||||
})
|
||||
expect(
|
||||
screen.queryByRole('combobox', {
|
||||
name: /role/i,
|
||||
name: 'Role',
|
||||
})
|
||||
).to.be.null
|
||||
expect(
|
||||
screen.queryByRole('combobox', {
|
||||
name: /department/i,
|
||||
name: 'Department',
|
||||
})
|
||||
).to.be.null
|
||||
})
|
||||
@@ -646,7 +645,7 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
@@ -659,7 +658,7 @@ describe('<EmailsSection />', function () {
|
||||
await userEvent.click(button)
|
||||
|
||||
await userEvent.type(
|
||||
screen.getByLabelText(/email/i, { selector: 'input' }),
|
||||
screen.getByRole('textbox', { name: 'Email' }),
|
||||
`user@${hostnameFirstChar}`
|
||||
)
|
||||
|
||||
@@ -686,16 +685,16 @@ describe('<EmailsSection />', function () {
|
||||
.post('/user/emails/confirm-secondary', 200)
|
||||
|
||||
await userEvent.type(
|
||||
screen.getByRole('combobox', { name: /role/i }),
|
||||
screen.getByRole('combobox', { name: 'Role' }),
|
||||
userEmailData.affiliation.role!
|
||||
)
|
||||
await userEvent.type(
|
||||
screen.getByRole('combobox', { name: /department/i }),
|
||||
screen.getByRole('combobox', { name: 'Department' }),
|
||||
userEmailData.affiliation.department!
|
||||
)
|
||||
await userEvent.click(
|
||||
screen.getByRole('button', {
|
||||
name: /add new email/i,
|
||||
name: 'Add new email',
|
||||
})
|
||||
)
|
||||
|
||||
@@ -743,12 +742,12 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
@@ -786,12 +785,12 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
@@ -833,12 +832,12 @@ describe('<EmailsSection />', function () {
|
||||
render(<EmailsSection />)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: /add another email/i,
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByLabelText(/email/i, { selector: 'input' })
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
|
||||
@@ -61,17 +61,17 @@ describe('<LinkingSection />', function () {
|
||||
|
||||
screen.getByText('Google')
|
||||
screen.getByText('Log in with Google.')
|
||||
screen.getByRole('button', { name: /unlink/i })
|
||||
screen.getByRole('button', { name: 'Unlink Google' })
|
||||
|
||||
screen.getByText('ORCID')
|
||||
screen.getByText(
|
||||
/Securely establish your identity by linking your ORCID iD/
|
||||
)
|
||||
const helpLink = screen.getByRole('link', {
|
||||
name: /learn more about orcid/i,
|
||||
name: 'Learn more about ORCID',
|
||||
})
|
||||
expect(helpLink.getAttribute('href')).to.equal('/blog/434')
|
||||
const linkButton = screen.getByRole('link', { name: /link orcid/i })
|
||||
const linkButton = screen.getByRole('link', { name: 'Link ORCID' })
|
||||
expect(linkButton.getAttribute('href')).to.equal('/auth/orcid?intent=link')
|
||||
})
|
||||
|
||||
|
||||
+13
-5
@@ -33,7 +33,9 @@ describe('<IntegrationLinkingWidgetTest/>', function () {
|
||||
})
|
||||
|
||||
it('should render an upgrade link and track clicks', function () {
|
||||
const upgradeLink = screen.getByRole('link', { name: /upgrade/i })
|
||||
const upgradeLink = screen.getByRole('link', {
|
||||
name: 'Integration Upgrade',
|
||||
})
|
||||
expect(upgradeLink.getAttribute('href')).to.equal(
|
||||
'/user/subscription/plans'
|
||||
)
|
||||
@@ -52,7 +54,9 @@ describe('<IntegrationLinkingWidgetTest/>', function () {
|
||||
|
||||
it('should render a link to initiate integration linking', function () {
|
||||
expect(
|
||||
screen.getByRole('link', { name: 'Link' }).getAttribute('href')
|
||||
screen
|
||||
.getByRole('link', { name: 'Link Integration' })
|
||||
.getAttribute('href')
|
||||
).to.equal('/link')
|
||||
})
|
||||
|
||||
@@ -86,11 +90,13 @@ describe('<IntegrationLinkingWidgetTest/>', function () {
|
||||
})
|
||||
|
||||
it('should display an `unlink` button', function () {
|
||||
screen.getByRole('button', { name: 'Unlink' })
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
})
|
||||
|
||||
it('should open a modal with a link to confirm integration unlinking', function () {
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Unlink' }))
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
const withinModal = within(screen.getByRole('dialog'))
|
||||
withinModal.getByText('confirm unlink')
|
||||
withinModal.getByText('you will be unlinked')
|
||||
@@ -99,7 +105,9 @@ describe('<IntegrationLinkingWidgetTest/>', function () {
|
||||
})
|
||||
|
||||
it('should cancel unlinking when clicking "cancel" in the confirmation modal', async function () {
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Unlink' }))
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
screen.getByText('confirm unlink')
|
||||
const cancelBtn = screen.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
|
||||
+28
-16
@@ -13,8 +13,8 @@ import { SSOLinkingWidget } from '../../../../../../frontend/js/features/setting
|
||||
describe('<SSOLinkingWidget />', function () {
|
||||
const defaultProps = {
|
||||
providerId: 'integration_id',
|
||||
title: 'integration',
|
||||
description: 'integration description',
|
||||
title: 'Integration',
|
||||
description: 'Integration description',
|
||||
helpPath: '/help/integration',
|
||||
linkPath: '/integration/link',
|
||||
onUnlink: () => Promise.resolve(),
|
||||
@@ -22,10 +22,12 @@ describe('<SSOLinkingWidget />', function () {
|
||||
|
||||
it('should render', function () {
|
||||
render(<SSOLinkingWidget {...defaultProps} />)
|
||||
screen.getByText('integration')
|
||||
screen.getByText('integration description')
|
||||
screen.getByText('Integration')
|
||||
screen.getByText('Integration description')
|
||||
expect(
|
||||
screen.getByRole('link', { name: /learn more/i }).getAttribute('href')
|
||||
screen
|
||||
.getByRole('link', { name: 'Learn more about Integration' })
|
||||
.getAttribute('href')
|
||||
).to.equal('/help/integration')
|
||||
})
|
||||
|
||||
@@ -33,7 +35,9 @@ describe('<SSOLinkingWidget />', function () {
|
||||
it('should render a link to `linkPath`', function () {
|
||||
render(<SSOLinkingWidget {...defaultProps} linked={false} />)
|
||||
expect(
|
||||
screen.getByRole('link', { name: /link/i }).getAttribute('href')
|
||||
screen
|
||||
.getByRole('link', { name: 'Link Integration' })
|
||||
.getAttribute('href')
|
||||
).to.equal('/integration/link?intent=link')
|
||||
})
|
||||
})
|
||||
@@ -49,19 +53,23 @@ describe('<SSOLinkingWidget />', function () {
|
||||
})
|
||||
|
||||
it('should display an `unlink` button', function () {
|
||||
screen.getByRole('button', { name: /unlink/i })
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
})
|
||||
|
||||
it('should open a modal to confirm integration unlinking', function () {
|
||||
fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
|
||||
screen.getByText('Unlink integration Account')
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
screen.getByText('Unlink Integration Account')
|
||||
screen.getByText(
|
||||
'Warning: When you unlink your account from integration you will not be able to sign in using integration anymore.'
|
||||
'Warning: When you unlink your account from Integration you will not be able to sign in using Integration anymore.'
|
||||
)
|
||||
})
|
||||
|
||||
it('should cancel unlinking when clicking cancel in the confirmation modal', async function () {
|
||||
fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
const cancelBtn = screen.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
hidden: false,
|
||||
@@ -80,9 +88,11 @@ describe('<SSOLinkingWidget />', function () {
|
||||
render(
|
||||
<SSOLinkingWidget {...defaultProps} linked onUnlink={unlinkFunction} />
|
||||
)
|
||||
fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
confirmBtn = within(screen.getByRole('dialog')).getByRole('button', {
|
||||
name: /unlink/i,
|
||||
name: 'Unlink',
|
||||
hidden: false,
|
||||
})
|
||||
})
|
||||
@@ -114,11 +124,13 @@ describe('<SSOLinkingWidget />', function () {
|
||||
render(
|
||||
<SSOLinkingWidget {...defaultProps} linked onUnlink={unlinkFunction} />
|
||||
)
|
||||
fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
|
||||
fireEvent.click(
|
||||
screen.getByRole('button', { name: 'Unlink Integration' })
|
||||
)
|
||||
const confirmBtn = within(screen.getByRole('dialog')).getByRole(
|
||||
'button',
|
||||
{
|
||||
name: /unlink/i,
|
||||
name: 'Unlink',
|
||||
hidden: false,
|
||||
}
|
||||
)
|
||||
@@ -130,7 +142,7 @@ describe('<SSOLinkingWidget />', function () {
|
||||
})
|
||||
|
||||
it('should display the unlink button ', async function () {
|
||||
await screen.findByRole('button', { name: /unlink/i })
|
||||
await screen.findByRole('button', { name: 'Unlink Integration' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user