mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #18543 from overleaf/jpa-server-pro-test-templates
[server-pro] tests: add tests for templates feature GitOrigin-RevId: b36482af924e306207cbdedc1a8d1d548272ee77
This commit is contained in:
parent
2754c90ea6
commit
5a1cff55bc
7 changed files with 273 additions and 9 deletions
|
@ -258,6 +258,7 @@ Hello world
|
||||||
cy.visit('/project')
|
cy.visit('/project')
|
||||||
createProject('maybe git')
|
createProject('maybe git')
|
||||||
cy.get('header').findByText('Menu').click()
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Word Count') // wait for lazy loading
|
||||||
cy.findByText('Sync').should('not.exist')
|
cy.findByText('Sync').should('not.exist')
|
||||||
cy.findByText('Git').should('not.exist')
|
cy.findByText('Git').should('not.exist')
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,8 +2,14 @@ import { reconfigure } from './hostAdminClient'
|
||||||
|
|
||||||
let lastConfig: string
|
let lastConfig: string
|
||||||
|
|
||||||
export function startWith({ pro = false, version = 'latest', vars = {} }) {
|
export function startWith({
|
||||||
|
pro = false,
|
||||||
|
version = 'latest',
|
||||||
|
vars = {},
|
||||||
|
varsFn = () => ({}),
|
||||||
|
}) {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
|
Object.assign(vars, varsFn())
|
||||||
const cfg = JSON.stringify({ pro, version, vars })
|
const cfg = JSON.stringify({ pro, version, vars })
|
||||||
if (lastConfig === cfg) return
|
if (lastConfig === cfg) return
|
||||||
|
|
||||||
|
|
|
@ -52,13 +52,18 @@ export function ensureUserExists({
|
||||||
}
|
}
|
||||||
|
|
||||||
export function login(username: string, password = DEFAULT_PASSWORD) {
|
export function login(username: string, password = DEFAULT_PASSWORD) {
|
||||||
cy.session([username, password, new Date()], () => {
|
const id = [username, password, new Date()]
|
||||||
cy.visit('/login')
|
function startOrResumeSession() {
|
||||||
cy.get('input[name="email"]').type(username)
|
cy.session(id, () => {
|
||||||
cy.get('input[name="password"]').type(password)
|
cy.visit('/login')
|
||||||
cy.findByRole('button', { name: 'Login' }).click()
|
cy.get('input[name="email"]').type(username)
|
||||||
cy.url().should('contain', '/project')
|
cy.get('input[name="password"]').type(password)
|
||||||
})
|
cy.findByRole('button', { name: 'Login' }).click()
|
||||||
|
cy.url().should('contain', '/project')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
startOrResumeSession()
|
||||||
|
return startOrResumeSession
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activateUser(url: string, password = DEFAULT_PASSWORD) {
|
export function activateUser(url: string, password = DEFAULT_PASSWORD) {
|
||||||
|
|
|
@ -147,6 +147,8 @@ const allowedVars = Joi.object(
|
||||||
'SANDBOXED_COMPILES',
|
'SANDBOXED_COMPILES',
|
||||||
'SANDBOXED_COMPILES_SIBLING_CONTAINERS',
|
'SANDBOXED_COMPILES_SIBLING_CONTAINERS',
|
||||||
'ALL_TEX_LIVE_DOCKER_IMAGE_NAMES',
|
'ALL_TEX_LIVE_DOCKER_IMAGE_NAMES',
|
||||||
|
'OVERLEAF_TEMPLATES_USER_ID',
|
||||||
|
'OVERLEAF_NEW_PROJECT_TEMPLATE_LINKS',
|
||||||
].map(name => [name, Joi.string()])
|
].map(name => [name, Joi.string()])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -61,6 +61,7 @@ describe('SandboxedCompiles', function () {
|
||||||
cy.get('[aria-label="View logs"]').click()
|
cy.get('[aria-label="View logs"]').click()
|
||||||
cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2024\) /)
|
cy.findByText(/This is pdfTeX, Version .+ \(TeX Live 2024\) /)
|
||||||
cy.get('header').findByText('Menu').click()
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Word Count') // wait for lazy loading
|
||||||
cy.findByText('TeX Live version').should('not.exist')
|
cy.findByText('TeX Live version').should('not.exist')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
249
server-ce/test/templates.spec.ts
Normal file
249
server-ce/test/templates.spec.ts
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
import { startWith } from './helpers/config'
|
||||||
|
import { ensureUserExists, login } from './helpers/login'
|
||||||
|
import { createProject } from './helpers/project'
|
||||||
|
|
||||||
|
const WITHOUT_PROJECTS_USER = 'user-without-projects@example.com'
|
||||||
|
const ADMIN_USER = 'admin@example.com'
|
||||||
|
const REGULAR_USER = 'user@example.com'
|
||||||
|
const TEMPLATES_USER = 'templates@example.com'
|
||||||
|
|
||||||
|
describe('Templates', () => {
|
||||||
|
ensureUserExists({ email: TEMPLATES_USER })
|
||||||
|
ensureUserExists({ email: WITHOUT_PROJECTS_USER })
|
||||||
|
|
||||||
|
let OVERLEAF_TEMPLATES_USER_ID: string
|
||||||
|
before(function () {
|
||||||
|
login(TEMPLATES_USER)
|
||||||
|
cy.visit('/')
|
||||||
|
cy.get('meta[name="ol-user_id"]').then(el => {
|
||||||
|
OVERLEAF_TEMPLATES_USER_ID = el.attr('content')!
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function varsFn() {
|
||||||
|
return {
|
||||||
|
OVERLEAF_TEMPLATES_USER_ID,
|
||||||
|
OVERLEAF_NEW_PROJECT_TEMPLATE_LINKS:
|
||||||
|
'[{"name":"All Templates","url":"/templates/all"}]',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('enabled in Server Pro', () => {
|
||||||
|
startWith({
|
||||||
|
pro: true,
|
||||||
|
varsFn,
|
||||||
|
})
|
||||||
|
ensureUserExists({ email: REGULAR_USER })
|
||||||
|
ensureUserExists({ email: ADMIN_USER, isAdmin: true })
|
||||||
|
|
||||||
|
it('should show templates link on welcome page', () => {
|
||||||
|
login(WITHOUT_PROJECTS_USER)
|
||||||
|
cy.visit('/')
|
||||||
|
cy.findByText('Browse templates').click()
|
||||||
|
cy.url().should('match', /\/templates$/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should have templates feature', () => {
|
||||||
|
const resumeTemplatesUserSession = login(TEMPLATES_USER)
|
||||||
|
const name = `Template ${Date.now()}`
|
||||||
|
const description = `Template Description ${Date.now()}`
|
||||||
|
|
||||||
|
cy.visit('/')
|
||||||
|
createProject(name).as('templateProjectId')
|
||||||
|
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Manage Template').click()
|
||||||
|
|
||||||
|
cy.findByText('Template Description')
|
||||||
|
.click()
|
||||||
|
.parent()
|
||||||
|
.get('textarea')
|
||||||
|
.type(description)
|
||||||
|
cy.findByText('Publish').click()
|
||||||
|
cy.findByText('Publishing…').should('be.disabled')
|
||||||
|
cy.findByText('Publish').should('not.exist')
|
||||||
|
cy.findByText('Unpublish', { timeout: 10_000 })
|
||||||
|
cy.findByText('Republish')
|
||||||
|
|
||||||
|
cy.findByText('View it in the template gallery').click()
|
||||||
|
cy.url()
|
||||||
|
.should('match', /\/templates\/[a-f0-9]{24}$/)
|
||||||
|
.as('templateURL')
|
||||||
|
|
||||||
|
cy.findAllByText(name).first().should('exist')
|
||||||
|
cy.findByText(description)
|
||||||
|
cy.findByText('Open as Template')
|
||||||
|
cy.findByText('Unpublish')
|
||||||
|
cy.findByText('Republish')
|
||||||
|
cy.get('img')
|
||||||
|
.should('have.attr', 'src')
|
||||||
|
.and('match', /\/v\/0\//)
|
||||||
|
cy.findByText('Republish').click()
|
||||||
|
cy.findByText('Publishing…').parent().should('be.disabled')
|
||||||
|
cy.findByText('Republish', { timeout: 10_000 })
|
||||||
|
cy.get('img', { timeout: 10_000 })
|
||||||
|
.should('have.attr', 'src')
|
||||||
|
.and('match', /\/v\/1\//)
|
||||||
|
|
||||||
|
// custom tag
|
||||||
|
const tagName = `${Date.now()}`
|
||||||
|
cy.visit('/')
|
||||||
|
cy.findByText(name)
|
||||||
|
.parent()
|
||||||
|
.parent()
|
||||||
|
.within(() => cy.get('input[type="checkbox"]').first().check())
|
||||||
|
cy.get('.project-list-sidebar-react').within(() => {
|
||||||
|
cy.findAllByText('New Tag').first().click()
|
||||||
|
})
|
||||||
|
cy.focused().type(tagName)
|
||||||
|
cy.findByText('Create').click()
|
||||||
|
cy.get('.project-list-sidebar-react').within(() => {
|
||||||
|
cy.findByText(tagName)
|
||||||
|
.parent()
|
||||||
|
.within(() => cy.get('.name').should('have.text', `${tagName} (1)`))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check listing
|
||||||
|
cy.visit('/templates')
|
||||||
|
cy.findByText(tagName)
|
||||||
|
cy.visit('/templates/all')
|
||||||
|
cy.findByText(name)
|
||||||
|
cy.visit(`/templates/${tagName}`)
|
||||||
|
cy.findByText(name)
|
||||||
|
|
||||||
|
// Unpublish via template page
|
||||||
|
cy.get('@templateURL').then(url => cy.visit(`${url}`))
|
||||||
|
cy.findByText('Unpublish').click()
|
||||||
|
cy.url().should('match', /\/templates$/)
|
||||||
|
cy.get('@templateURL').then(url =>
|
||||||
|
cy.visit(`${url}`, {
|
||||||
|
failOnStatusCode: false,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
cy.findByText('Not found')
|
||||||
|
cy.visit('/templates/all')
|
||||||
|
cy.findByText(name).should('not.exist')
|
||||||
|
cy.visit(`/templates/${tagName}`)
|
||||||
|
cy.findByText(name).should('not.exist')
|
||||||
|
|
||||||
|
// Publish again
|
||||||
|
cy.get('@templateProjectId').then(projectId =>
|
||||||
|
cy.visit(`/project/${projectId}`)
|
||||||
|
)
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Manage Template').click()
|
||||||
|
cy.findByText('Publish').click()
|
||||||
|
cy.findByText('Unpublish', { timeout: 10_000 })
|
||||||
|
|
||||||
|
// Should assign a new template id
|
||||||
|
cy.findByText('View it in the template gallery').click()
|
||||||
|
cy.url()
|
||||||
|
.should('match', /\/templates\/[a-f0-9]{24}$/)
|
||||||
|
.as('newTemplateURL')
|
||||||
|
cy.get('@newTemplateURL').then(newURL => {
|
||||||
|
cy.get('@templateURL').then(prevURL => {
|
||||||
|
expect(newURL).to.match(/\/templates\/[a-f0-9]{24}$/)
|
||||||
|
expect(prevURL).to.not.equal(newURL)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Open project from template
|
||||||
|
login(REGULAR_USER)
|
||||||
|
cy.visit('/templates')
|
||||||
|
cy.findByText(tagName).click()
|
||||||
|
cy.findByText(name).click()
|
||||||
|
cy.findByText('Open as Template').click()
|
||||||
|
cy.url().should('match', /\/project\/[a-f0-9]{24}$/)
|
||||||
|
cy.get('.project-name').findByText(name)
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Word Count') // wait for lazy loading
|
||||||
|
cy.findByText('Manage Template').should('not.exist')
|
||||||
|
|
||||||
|
// Check management as regular user
|
||||||
|
cy.get('@newTemplateURL').then(url => cy.visit(`${url}`))
|
||||||
|
cy.findByText('Open as Template')
|
||||||
|
cy.findByText('Unpublish').should('not.exist')
|
||||||
|
cy.findByText('Republish').should('not.exist')
|
||||||
|
|
||||||
|
// Check management as admin user
|
||||||
|
login(ADMIN_USER)
|
||||||
|
cy.get('@newTemplateURL').then(url => cy.visit(`${url}`))
|
||||||
|
cy.findByText('Open as Template')
|
||||||
|
cy.findByText('Unpublish')
|
||||||
|
cy.findByText('Republish')
|
||||||
|
cy.get('@templateProjectId').then(projectId =>
|
||||||
|
cy.visit(`/project/${projectId}`)
|
||||||
|
)
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Manage Template').click()
|
||||||
|
cy.findByText('Unpublish')
|
||||||
|
|
||||||
|
resumeTemplatesUserSession()
|
||||||
|
|
||||||
|
// Unpublish via editor
|
||||||
|
cy.get('@templateProjectId').then(projectId =>
|
||||||
|
cy.visit(`/project/${projectId}`)
|
||||||
|
)
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Manage Template').click()
|
||||||
|
cy.findByText('Unpublish').click()
|
||||||
|
cy.findByText('Publish')
|
||||||
|
cy.visit('/templates/all')
|
||||||
|
cy.findByText(name).should('not.exist')
|
||||||
|
|
||||||
|
// check for template links, after creating the first project
|
||||||
|
cy.visit('/')
|
||||||
|
cy.findAllByRole('button')
|
||||||
|
.contains(/new project/i)
|
||||||
|
.click()
|
||||||
|
cy.findAllByText('All Templates')
|
||||||
|
.first()
|
||||||
|
.should('have.attr', 'href', '/templates/all')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function checkDisabled() {
|
||||||
|
it('should not have templates feature', () => {
|
||||||
|
login(TEMPLATES_USER)
|
||||||
|
|
||||||
|
cy.visit('/')
|
||||||
|
createProject('maybe templates')
|
||||||
|
|
||||||
|
cy.get('header').findByText('Menu').click()
|
||||||
|
cy.findByText('Word Count') // wait for lazy loading
|
||||||
|
cy.findByText('Manage Template').should('not.exist')
|
||||||
|
|
||||||
|
cy.visit('/templates', { failOnStatusCode: false })
|
||||||
|
cy.findByText('Not found')
|
||||||
|
cy.visit('/templates/all', { failOnStatusCode: false })
|
||||||
|
cy.findByText('Not found')
|
||||||
|
|
||||||
|
// check for template links, after creating the first project
|
||||||
|
cy.visit('/')
|
||||||
|
cy.findAllByRole('button')
|
||||||
|
.contains(/new project/i)
|
||||||
|
.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('Browse templates').should('not.exist')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('disabled Server Pro', () => {
|
||||||
|
startWith({ pro: true })
|
||||||
|
checkDisabled()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('unavailable in CE', () => {
|
||||||
|
startWith({
|
||||||
|
pro: false,
|
||||||
|
varsFn,
|
||||||
|
})
|
||||||
|
checkDisabled()
|
||||||
|
})
|
||||||
|
})
|
|
@ -65,7 +65,7 @@ const Features = {
|
||||||
case 'oauth':
|
case 'oauth':
|
||||||
return Boolean(Settings.oauth)
|
return Boolean(Settings.oauth)
|
||||||
case 'templates-server-pro':
|
case 'templates-server-pro':
|
||||||
return Boolean(Settings.templates)
|
return Boolean(Settings.templates?.user_id)
|
||||||
case 'affiliations':
|
case 'affiliations':
|
||||||
case 'analytics':
|
case 'analytics':
|
||||||
return Boolean(_.get(Settings, ['apis', 'v1', 'url']))
|
return Boolean(_.get(Settings, ['apis', 'v1', 'url']))
|
||||||
|
|
Loading…
Reference in a new issue