mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
[clsi-cache] check compiler settings before using compile from cache (#24845)
* [web] provide an actual rootFolder from EditorProviders in tests - Fixup SocketIOMock and ShareJS mocks to provide the complete interface - Extend SocketIOMock interface to count event listeners - Fixup test that did not expect to find a working rootDoc * [web] expose imageName from ProjectContext * [clsi-cache] check compiler settings before using compile from cache * [web] avoid fetching initial compile from clsi-cache in PDF detach tab GitOrigin-RevId: e3c754a7ceca55f03a317e1bc8ae45ed12cc2f02
This commit is contained in:
@@ -28,7 +28,19 @@ const Layout: FC<{ layout: IdeLayout; view?: IdeView }> = ({
|
||||
}
|
||||
|
||||
describe('<PdfPreview/>', function () {
|
||||
let projectId: string
|
||||
beforeEach(function () {
|
||||
/**
|
||||
* There are time sensitive tests in this test suite. They need to wait for a Promise before resolving a request.
|
||||
*
|
||||
* Using a promise across the test-env (browser) vs stub-env (server) causes additional latency.
|
||||
*
|
||||
* This latency seems to stack up when adding more intercepts for the same path. Using static responses for some of these intercepts does not help.
|
||||
*
|
||||
* All of that seems like a bug in Cypress. For now just work around it by using a unique projectId for each intercept.
|
||||
*/
|
||||
projectId = Math.random().toString().slice(2)
|
||||
|
||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||
window.metaAttributesCache.set(
|
||||
'ol-compilesUserContentDomain',
|
||||
@@ -61,7 +73,12 @@ describe('<PdfPreview/>', function () {
|
||||
})
|
||||
|
||||
it('uses the cache when available', function () {
|
||||
cy.interceptCompile({ prefix: 'compile', times: 1, cached: true })
|
||||
cy.interceptCompile({
|
||||
prefix: 'compile',
|
||||
times: 1,
|
||||
cached: true,
|
||||
regular: false,
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
|
||||
@@ -74,13 +91,18 @@ describe('<PdfPreview/>', function () {
|
||||
)
|
||||
|
||||
// wait for "compile from cache on load" to finish
|
||||
cy.waitForCompile({ pdf: true, cached: true })
|
||||
cy.waitForCompile({ pdf: true, cached: true, regular: false })
|
||||
|
||||
cy.contains('Your Paper')
|
||||
})
|
||||
|
||||
it('uses the cache when available then compiles', function () {
|
||||
cy.interceptCompile({ prefix: 'compile', times: 1, cached: true })
|
||||
cy.interceptCompile({
|
||||
prefix: 'compile',
|
||||
times: 1,
|
||||
cached: true,
|
||||
regular: false,
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
|
||||
@@ -93,7 +115,7 @@ describe('<PdfPreview/>', function () {
|
||||
)
|
||||
|
||||
// wait for "compile from cache on load" to finish
|
||||
cy.waitForCompile({ pdf: true, cached: true })
|
||||
cy.waitForCompile({ pdf: true, cached: true, regular: false })
|
||||
cy.contains('Your Paper')
|
||||
|
||||
// Then trigger a new compile
|
||||
@@ -112,6 +134,154 @@ describe('<PdfPreview/>', function () {
|
||||
cy.contains('Modern Authoring Tools for Science')
|
||||
})
|
||||
|
||||
describe('racing compile from cache and regular compile trigger', function () {
|
||||
for (const [timing] of ['before rendering', 'after rendering']) {
|
||||
it(`replaces the compile from cache with a regular compile - ${timing}`, function () {
|
||||
const requestedOnce = new Set()
|
||||
;['log', 'pdf', 'blg'].forEach(ext => {
|
||||
cy.intercept({ pathname: `/build/*/output.${ext}` }, req => {
|
||||
if (requestedOnce.has(ext)) {
|
||||
throw new Error(
|
||||
`compile from cache triggered extra ${ext} request: ${req.url}`
|
||||
)
|
||||
}
|
||||
requestedOnce.add(ext)
|
||||
req.reply({ fixture: `build/output.${ext},null` })
|
||||
}).as(`compile-${ext}`)
|
||||
})
|
||||
const { promise, resolve } = Promise.withResolvers<void>()
|
||||
cy.interceptCompileFromCacheRequest({
|
||||
promise,
|
||||
times: 1,
|
||||
}).as('cached-compile')
|
||||
cy.interceptCompileRequest().as('compile')
|
||||
|
||||
const scope = mockScope()
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope} projectId={projectId}>
|
||||
<div className="pdf-viewer">
|
||||
<PdfPreview />
|
||||
</div>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
// press the Recompile button => compile
|
||||
cy.findByRole('button', { name: 'Recompile' }).click()
|
||||
|
||||
if (timing === 'before rendering') {
|
||||
cy.then(() => resolve())
|
||||
cy.wait('@cached-compile')
|
||||
}
|
||||
|
||||
// wait for rendering to finish
|
||||
cy.waitForCompile({ pdf: true, cached: false })
|
||||
|
||||
if (timing === 'after rendering') {
|
||||
cy.then(() => resolve())
|
||||
cy.wait('@cached-compile')
|
||||
}
|
||||
|
||||
cy.contains('Your Paper')
|
||||
cy.then(() => Array.from(requestedOnce).sort().join(',')).should(
|
||||
'equal',
|
||||
'blg,log,pdf'
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('clsi-cache project settings validation', function () {
|
||||
const cases = {
|
||||
// Flaky, skip for now
|
||||
'uses compile from cache when nothing changed': {
|
||||
cached: true,
|
||||
setup: () => {},
|
||||
props: {},
|
||||
},
|
||||
'ignores the compile from cache when imageName changed': {
|
||||
cached: false,
|
||||
setup: () => {},
|
||||
props: {
|
||||
imageName: 'texlive-full:2025.1',
|
||||
},
|
||||
},
|
||||
'ignores the compile from cache when compiler changed': {
|
||||
cached: false,
|
||||
setup: () => {},
|
||||
props: {
|
||||
compiler: 'lualatex',
|
||||
},
|
||||
},
|
||||
'ignores the compile from cache when draft mode changed': {
|
||||
cached: false,
|
||||
setup: () => {
|
||||
cy.window().then(w =>
|
||||
w.localStorage.setItem(`draft:${projectId}`, 'true')
|
||||
)
|
||||
},
|
||||
props: {},
|
||||
},
|
||||
'ignores the compile from cache when stopOnFirstError mode changed': {
|
||||
cached: false,
|
||||
setup: () => {
|
||||
cy.window().then(w =>
|
||||
w.localStorage.setItem(`stop_on_first_error:${projectId}`, 'true')
|
||||
)
|
||||
},
|
||||
props: {},
|
||||
},
|
||||
'ignores the compile from cache when rootDoc changed': {
|
||||
cached: false,
|
||||
setup: () => {},
|
||||
props: {
|
||||
rootDocId: 'new-root-doc-id',
|
||||
rootFolder: [
|
||||
{
|
||||
_id: 'root-folder-id',
|
||||
name: 'rootFolder',
|
||||
docs: [
|
||||
{
|
||||
_id: '_root_doc_id',
|
||||
name: 'main.tex',
|
||||
},
|
||||
{
|
||||
_id: 'new-root-doc-id',
|
||||
name: 'new-main.tex',
|
||||
},
|
||||
],
|
||||
folders: [],
|
||||
fileRefs: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
Object.entries(cases).forEach(([name, { cached, setup, props }]) => {
|
||||
it(name, function () {
|
||||
cy.interceptCompile({
|
||||
cached: true,
|
||||
regular: !cached,
|
||||
})
|
||||
|
||||
const scope = mockScope()
|
||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', false)
|
||||
setup()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope} projectId={projectId} {...props}>
|
||||
<div className="pdf-viewer">
|
||||
<PdfPreview />
|
||||
</div>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
// wait for compile to finish
|
||||
cy.waitForCompile({ pdf: true, cached, regular: !cached })
|
||||
cy.contains('Your Paper')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('runs a compile when the Recompile button is pressed', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ export const mockScope = () => ({
|
||||
sharejs_doc: {
|
||||
doc_id: 'test-doc',
|
||||
getSnapshot: () => 'some doc content',
|
||||
hasBufferedOps: () => false,
|
||||
},
|
||||
view: new EditorView({
|
||||
doc: '\\documentclass{article}',
|
||||
|
||||
@@ -56,8 +56,7 @@ describe('ChatContext', function () {
|
||||
it('subscribes when mounted', function () {
|
||||
const socket = new SocketIOMock()
|
||||
renderChatContextHook({ socket })
|
||||
// Assert that there is 1 listener
|
||||
expect(socket.events['new-chat-message']).to.have.length(1)
|
||||
expect(socket.countEventListeners('new-chat-message')).to.equal(1)
|
||||
})
|
||||
|
||||
it('unsubscribes when unmounted', function () {
|
||||
@@ -66,8 +65,7 @@ describe('ChatContext', function () {
|
||||
|
||||
unmount()
|
||||
|
||||
// Assert that there is 0 listeners
|
||||
expect(socket.events['new-chat-message'].length).to.equal(0)
|
||||
expect(socket.countEventListeners('new-chat-message')).to.equal(0)
|
||||
})
|
||||
|
||||
it('adds received messages to the list', async function () {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { FileTreeProvider } from '../helpers/file-tree-provider'
|
||||
describe('<FileTreeToolbar/>', function () {
|
||||
it('without selected files', function () {
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<EditorProviders rootDocId="">
|
||||
<FileTreeProvider>
|
||||
<FileTreeToolbar />
|
||||
</FileTreeProvider>
|
||||
|
||||
@@ -44,6 +44,8 @@ export function EditorProviders({
|
||||
email: 'owner@example.com',
|
||||
},
|
||||
rootDocId = '_root_doc_id',
|
||||
imageName = 'texlive-full:2024.1',
|
||||
compiler = 'pdflatex',
|
||||
socket = new SocketIOMock(),
|
||||
isRestrictedTokenMember = false,
|
||||
clsiServerId = '1234',
|
||||
@@ -58,7 +60,12 @@ export function EditorProviders({
|
||||
{
|
||||
_id: 'root-folder-id',
|
||||
name: 'rootFolder',
|
||||
docs: [],
|
||||
docs: [
|
||||
{
|
||||
_id: '_root_doc_id',
|
||||
name: 'main.tex',
|
||||
},
|
||||
],
|
||||
folders: [],
|
||||
fileRefs: [],
|
||||
},
|
||||
@@ -99,6 +106,10 @@ export function EditorProviders({
|
||||
sharejs_doc: {
|
||||
doc_id: 'test-doc',
|
||||
getSnapshot: () => 'some doc content',
|
||||
hasBufferedOps: () => false,
|
||||
on: () => {},
|
||||
off: () => {},
|
||||
leaveAndCleanUpPromise: async () => {},
|
||||
},
|
||||
},
|
||||
project: {
|
||||
@@ -108,6 +119,8 @@ export function EditorProviders({
|
||||
features: projectFeatures,
|
||||
rootDoc_id: rootDocId,
|
||||
rootFolder,
|
||||
imageName,
|
||||
compiler,
|
||||
},
|
||||
ui,
|
||||
$watch: (path, callback) => {
|
||||
|
||||
Reference in New Issue
Block a user