diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 84353e56..9cc56eaf 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -26,6 +26,11 @@ jobs: restore-keys: | ${{ runner.os }}-node_modules-build- + - name: Lint + run: | + yarn install + yarn run lint + # Install NPM dependencies, cache them correctly # and run all Cypress tests - name: Cypress run diff --git a/cypress/integration/loadSite.spec.ts b/cypress/integration/loadSite.spec.ts index c83d6d14..57e3e397 100644 --- a/cypress/integration/loadSite.spec.ts +++ b/cypress/integration/loadSite.spec.ts @@ -1,3 +1,5 @@ +import { toBase64 } from 'js-base64'; + describe('Site Loads', () => { beforeEach(() => { cy.clearLocalStorage(); @@ -31,12 +33,29 @@ describe('Site Loads', () => { }); it('should prevent setting the "securityLevel" option via URL', () => { - const b64State = btoa( - `{"code":"graph TD\\nA[\\"\\"]","mermaid":"{\\"securityLevel\\": \\"loose\\", \\"theme\\": \\"forest\\"}","updateEditor":true,"autoSync":true,"updateDiagram":true}` + const b64State = toBase64( + `{"code":"graph TD\\nA[\\"\\"]","mermaid":"{\\"securityLevel\\": \\"loose\\", \\"theme\\": \\"forest\\"}","updateEditor":true,"autoSync":true,"updateDiagram":true}`, + true ); + cy.on('window:confirm', () => true); cy.visit(`/edit#${b64State}`); cy.contains('Config').click(); - cy.contains('forest').should('exist'); + cy.contains('forest'); cy.contains('securityLevel').should('not.exist'); + cy.get('#view').find('img').should('not.exist'); + cy.get('#view').contains(' { + const b64State = toBase64( + `{"code":"graph TD\\nA[\\"\\"]","mermaid":"{\\"securityLevel\\": \\"loose\\", \\"theme\\": \\"forest\\"}","updateEditor":true,"autoSync":true,"updateDiagram":true}`, + true + ); + cy.on('window:confirm', () => false); + cy.visit(`/edit#${b64State}`); + cy.contains('Config').click(); + cy.contains('forest'); + cy.contains('securityLevel'); + cy.get('#view').find('img').should('be.visible'); }); }); diff --git a/cypress/snapshots.js b/cypress/snapshots.js index e2663900..f769a8db 100644 --- a/cypress/snapshots.js +++ b/cypress/snapshots.js @@ -7,7 +7,7 @@ module.exports = { "1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":true,\"updateDiagram\":false}" } }, - "__version": "7.4.0", + "__version": "7.5.0", "Auto sync tests": { "should dim diagram when code is edited": { "1": "{\"code\":\"graph TD\\n A[Christmas] -->|Get money| B(Go shopping)\\n B --> C{Let me think}\\n C -->|One| D[Laptop]\\n C -->|Two| E[iPhone]\\n C -->|Three| F[fa:fa-car Car]\\n C --> Test\",\"mermaid\":\"{\\n \\\"theme\\\": \\\"default\\\"\\n}\",\"updateEditor\":false,\"autoSync\":false,\"updateDiagram\":false}" diff --git a/src/lib/components/view.svelte b/src/lib/components/view.svelte index 35e5cb31..7b3204e8 100644 --- a/src/lib/components/view.svelte +++ b/src/lib/components/view.svelte @@ -7,6 +7,7 @@ const mermaid: Mermaid = window.mermaid as unknown as Mermaid; let code = ''; + let config = ''; let container: HTMLDivElement; let error = false; let outOfSync = false; @@ -20,7 +21,12 @@ } outOfSync = false; manualUpdate = true; + if (code === state.code && config === state.mermaid) { + // Do not render if there is no change in Code/Config + return; + } code = state.code; + config = state.mermaid; const scroll = container.parentElement.parentElement.parentElement.scrollTop; delete container.dataset.processed; mermaid.initialize(Object.assign({}, JSON.parse(state.mermaid))); diff --git a/src/lib/util/state.ts b/src/lib/util/state.ts index d0f8ee82..3669b6ac 100644 --- a/src/lib/util/state.ts +++ b/src/lib/util/state.ts @@ -37,9 +37,14 @@ export const loadState = (data: string): void => { state = JSON.parse(stateStr); const mermaidConfig = typeof state.mermaid === 'string' ? JSON.parse(state.mermaid) : state.mermaid; - if(mermaidConfig.securityLevel) { - alert(`securityLevel was removed from config. Please add "securityLevel":"${mermaidConfig.securityLevel}" to your config if you trust the source of this Diagram`); - delete mermaidConfig.securityLevel; // Prevent setting overriding securityLevel when loading state to mitigate possible XSS attack + if ( + mermaidConfig.securityLevel && + mermaidConfig.securityLevel !== 'strict' && + confirm( + `Removing "securityLevel":"${mermaidConfig.securityLevel}" from the config for safety.\nClick Cancel if you trust the source of this Diagram.` + ) + ) { + delete mermaidConfig.securityLevel; // Prevent setting overriding securityLevel when loading state to mitigate possible XSS attack } state.mermaid = JSON.stringify(mermaidConfig, null, 2);