Switch the base framework from Create React App to Next.JS

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Renovate Bot 2021-12-25 15:44:24 +00:00 committed by Tilman Vatteroth
parent a979b6ffdd
commit 77a60c6c48
361 changed files with 5130 additions and 9605 deletions

1
.env.development Normal file
View file

@ -0,0 +1 @@
NEXT_PUBLIC_USE_MOCK_API=true

View file

@ -1 +1 @@
INLINE_RUNTIME_CHUNK=false NEXT_PUBLIC_USE_MOCK_API=false

1
.env.test Normal file
View file

@ -0,0 +1 @@
NEXT_PUBLIC_USE_MOCK_API=true

44
.eslintrc.json Normal file
View file

@ -0,0 +1,44 @@
{
"root": true,
"parserOptions": {
"tsconfigRootDir": "",
"project": [
"./tsconfig.json"
]
},
"rules": {
"no-use-before-define": "off",
"no-debugger": "warn",
"default-param-last": "off",
"@typescript-eslint/consistent-type-imports": [
"error",
{
"prefer": "type-imports",
"disallowTypeAnnotations": false
}
]
},
"plugins": [
"@typescript-eslint",
"testing-library"
],
"extends": [
"next/core-web-vitals",
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier"
],
"overrides": [
{
"files": [
"**/__tests__/**/*.[jt]s?(x)",
"**/?(*.)+(spec|test).[jt]s?(x)"
],
"extends": ["plugin:testing-library/react"]
}
]
}

View file

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node: [ '12', '14', '16' ] node: [ '14', '16' ]
name: Test and build with NodeJS ${{ matrix.node }} name: Test and build with NodeJS ${{ matrix.node }}
steps: steps:
- name: Checkout repository - name: Checkout repository
@ -38,6 +38,6 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: yarn install --frozen-lockfile --prefer-offline run: yarn install --frozen-lockfile --prefer-offline
- name: Test Project - name: Test Project
run: yarn test run: yarn test:ci
- name: Build project - name: Build project
run: yarn build:mock run: yarn build:mock

View file

@ -22,7 +22,7 @@ jobs:
uses: actions/cache@v2.1.7 uses: actions/cache@v2.1.7
id: build-cache id: build-cache
with: with:
path: build path: .next
key: build-${{ github.sha }} key: build-${{ github.sha }}
- name: Get yarn cache directory path - name: Get yarn cache directory path
@ -56,8 +56,8 @@ jobs:
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: build name: next-build
path: build path: .next
end2end: end2end:
name: Perform E2E Test in ${{ matrix.browser }} name: Perform E2E Test in ${{ matrix.browser }}
@ -79,13 +79,13 @@ jobs:
- name: Download built frontend - name: Download built frontend
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: build name: next-build
path: build path: .next
- uses: cypress-io/github-action@v2 - uses: cypress-io/github-action@v2
with: with:
browser: ${{ matrix.browser }} browser: ${{ matrix.browser }}
start: 'yarn serve:build' start: 'yarn start:ci'
parallel: true parallel: true
record: true record: true
group: "UI - ${{ matrix.browser }}" group: "UI - ${{ matrix.browser }}"

31
.gitignore vendored
View file

@ -15,23 +15,36 @@
# downloaded files during tests with cypress # downloaded files during tests with cypress
/cypress/downloads /cypress/downloads
# next.js
/.next/
/out/
# production # production
/build /build
# ide
.idea
!.idea/dictionaries/hedgedoc.xml
!.idea/copyright
!.idea/prettier.xml
# misc # misc
.DS_Store .DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local .env.local
.env.development.local .env.development.local
.env.test.local .env.test.local
.env.production.local .env.production.local
npm-debug.log* # vercel
yarn-debug.log* .vercel
yarn-error.log*
.eslintcache # typescript
*.tsbuildinfo
# IDE
.idea
!.idea/dictionaries/hedgedoc.xml
!.idea/copyright
!.idea/prettier.xml

11
.prettierrc.json Normal file
View file

@ -0,0 +1,11 @@
{
"parser": "typescript",
"singleQuote": true,
"jsxSingleQuote": true,
"semi": false,
"tabWidth": 2,
"trailingComma": "none",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always"
}

View file

@ -1,3 +1,3 @@
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: LicenseRef-HedgeDoc-Icon-Usage-Guidelines SPDX-License-Identifier: CC0-1.0

View file

@ -13,11 +13,12 @@ SPDX-License-Identifier: CC-BY-SA-4.0
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/hedgedoc/react-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hedgedoc/react-client/context:javascript) [![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/hedgedoc/react-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hedgedoc/react-client/context:javascript)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/hedgedoc/react-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hedgedoc/react-client/alerts/) [![Total alerts](https://img.shields.io/lgtm/alerts/g/hedgedoc/react-client.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hedgedoc/react-client/alerts/)
This is the new, improved and better looking frontend for HedgeDoc 2.0. This is the new, improved and better looking frontend for HedgeDoc 2.0. Our goal is to recreate the current frontend in
Our goal is to recreate the current frontend in react and to improve it. react and to improve it.
## Preparation ## Preparation
You need at least Node 12 (we recommend Node 16) and [yarn](https://yarnpkg.com/).
You need at least Node 14 (we recommend Node 16) and [yarn](https://yarnpkg.com/).
## Development mode ## Development mode
@ -25,13 +26,14 @@ You need at least Node 12 (we recommend Node 16) and [yarn](https://yarnpkg.com/
2. Go inside the repo (e.g. `cd hedgedoc-react-client`) 2. Go inside the repo (e.g. `cd hedgedoc-react-client`)
3. Run `yarn install` 3. Run `yarn install`
4. Either run 4. Either run
- `yarn start` - Calls only mocked version of the api. Doesn't need a HedgeDoc backend. - `yarn dev` - Calls only mocked version of the api. Doesn't need a HedgeDoc backend.
- `yarn start:for-real-backend` - Expects [a HedgeDoc backend server](https://github.com/hedgedoc/hedgedoc/tree/develop) running under [http://localhost:3000](http://localhost:3000)) - `yarn start:for-real-backend` -
Expects [a HedgeDoc backend server](https://github.com/hedgedoc/hedgedoc/tree/develop) running
under [http://localhost:3000](http://localhost:3000))
This should run the app in the development mode and open [http://localhost:3001](http://localhost:3001) in your browser. This should run the app in the development mode and open [http://localhost:3001](http://localhost:3001) in your browser.
The page will reload if you make edits. The page will reload if you make edits. You will also see any lint errors in the console.
You will also see any lint errors in the console.
### Tests ### Tests
@ -45,25 +47,28 @@ Unit testing is done via jest.
We use [cypress](https://cypress.io) for e2e tests. We use [cypress](https://cypress.io) for e2e tests.
1. Start the frontend with `yarn start:test` in dev test mode or build a test build with `yarn build:test` which you can serve with `yarn serve:build` 1. Start the frontend with `yarn dev:test` in dev test mode or build a test build with `yarn build:test` which you can
serve with `yarn serve:build`
Don't use the regular start/build command, or the tests will fail! Don't use the regular start/build command, or the tests will fail!
2. Run `yarn cy:open` to open the cypress test loader 2. Run `yarn cy:open` to open the cypress test loader
3. Choose your browser and test 3. Choose your browser and test
4. Let the tests run 4. Let the tests run
### Bundle analysis ### Bundle analysis
You can inspect the generated production-bundle files to look for optimization issues. You can inspect the generated production-bundle files to look for optimization issues.
1. Run `yarn analyze` 1. Run `yarn analyze`
2. Open the generated `build/report.html` in your favourite browser 2. Open the generated `.next/server/analyze/server.html` in your favourite browser
## Production mode ## Production mode
1. Clone this repo (e.g. `git clone https://github.com/hedgedoc/react-client.git hedgedoc-react-client`) 1. Clone this repo (e.g. `git clone https://github.com/hedgedoc/react-client.git hedgedoc-react-client`)
2. Go inside the repo (e.g. `cd hedgedoc-react-client`) 2. Go inside the repo (e.g. `cd hedgedoc-react-client`)
3. Run `yarn install` 3. Run `yarn install`
4. Run `yarn build:production` 4. Run `yarn build`
This will build the app in production mode and save it into the `build` folder. This will build the app in production mode and save it into the `.next` folder. The production build is optimized for
The production build is optimized for best performance, minimized best performance, minimized and the filenames include a hash value of the content. Don't edit them by hand!
and the filenames include a hash value of the content. Don't edit them by hand!
You can run the production build using the built-in server with `yarn start`.

View file

@ -1,10 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
if (!process.env.REACT_APP_BACKEND_BASE_URL) {
console.error("==============\nREACT_APP_BACKEND_BASE_URL not set.\n Use this task only if you want to create a production build with a real backend. Otherwise use build:mock\n==============");
process.exit(1);
}

View file

@ -1,31 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
const CopyPlugin = require('copy-webpack-plugin');
const { when } = require('@craco/craco');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
webpack: {
plugins: {
add: [
new CopyPlugin({
patterns: [
{ from: 'node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm', to: 'static/js' },
{ from: 'node_modules/@hpcc-js/wasm/dist/expatlib.wasm', to: 'static/js' },
{ from: 'node_modules/emoji-picker-element-data/en/emojibase/data.json', to: 'static/js/emoji-data.json' }
],
}),
...when(Boolean(process.env.ANALYZE), () => [
new BundleAnalyzerPlugin({
analyzerMode: "static",
generateStatsFile: true
})
], [])
]
}
}
}

View file

@ -18,7 +18,7 @@ describe('Autocompletion works for', () => {
cy.get('.CodeMirror-hints').should('not.exist') cy.get('.CodeMirror-hints').should('not.exist')
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line').contains('```abnf') cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line').contains('```abnf')
cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line').contains('```') cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line').contains('```')
cy.getMarkdownBody().findById('highlighted-code-block').should('exist') cy.getMarkdownBody().findByCypressId('highlighted-code-block').should('exist')
}) })
it('via doubleclick', () => { it('via doubleclick', () => {
cy.setCodemirrorContent('```') cy.setCodemirrorContent('```')
@ -26,7 +26,7 @@ describe('Autocompletion works for', () => {
cy.get('.CodeMirror-hints').should('not.exist') cy.get('.CodeMirror-hints').should('not.exist')
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line').contains('```abnf') cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line').contains('```abnf')
cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line').contains('```') cy.get('.CodeMirror-code > div:nth-of-type(3) > .CodeMirror-line').contains('```')
cy.getMarkdownBody().findById('highlighted-code-block').should('exist') cy.getMarkdownBody().findByCypressId('highlighted-code-block').should('exist')
}) })
}) })
@ -109,14 +109,14 @@ describe('Autocompletion works for', () => {
cy.get('@codeinput').type('{enter}') cy.get('@codeinput').type('{enter}')
cy.get('.CodeMirror-hints').should('not.exist') cy.get('.CodeMirror-hints').should('not.exist')
cy.get('.CodeMirror-activeline').contains('![image alt](https:// "title")') cy.get('.CodeMirror-activeline').contains('![image alt](https:// "title")')
cy.getMarkdownBody().find('.image-drop').should('exist') cy.getMarkdownBody().findByCypressId('image-placeholder-image-drop').should('exist')
}) })
it('via doubleclick', () => { it('via doubleclick', () => {
cy.setCodemirrorContent('!') cy.setCodemirrorContent('!')
cy.get('.CodeMirror-hints > li').first().dblclick() cy.get('.CodeMirror-hints > li').first().dblclick()
cy.get('.CodeMirror-hints').should('not.exist') cy.get('.CodeMirror-hints').should('not.exist')
cy.get('.CodeMirror-activeline').contains('![image alt](https:// "title")') cy.get('.CodeMirror-activeline').contains('![image alt](https:// "title")')
cy.getMarkdownBody().find('.image-drop').should('exist') cy.getMarkdownBody().findByCypressId('image-placeholder-image-drop').should('exist')
}) })
}) })

View file

@ -9,10 +9,14 @@ describe('Diagram codeblock ', () => {
cy.visitTestEditor() cy.visitTestEditor()
}) })
it('renders markmap', () => { /*
cy.setCodemirrorContent('```markmap\n- pro\n- contra\n```') TODO: Readd test after fixing https://github.com/hedgedoc/react-client/issues/1709
cy.getMarkdownBody().findById('markmap').children().should('be.visible')
}) it('renders markmap', () => {
cy.setCodemirrorContent('```markmap\n- pro\n- contra\n```')
cy.getMarkdownBody().findByCypressId('markmap').children().should('be.visible')
})
*/
it('renders vega-lite', () => { it('renders vega-lite', () => {
cy.setCodemirrorContent( cy.setCodemirrorContent(
@ -23,27 +27,27 @@ describe('Diagram codeblock ', () => {
it('renders graphviz', () => { it('renders graphviz', () => {
cy.setCodemirrorContent('```graphviz\ngraph {\na -- b\n}\n```') cy.setCodemirrorContent('```graphviz\ngraph {\na -- b\n}\n```')
cy.getMarkdownBody().findById('graphviz').children().should('be.visible') cy.getMarkdownBody().findByCypressId('graphviz').children().should('be.visible')
}) })
it('renders mermaid', () => { it('renders mermaid', () => {
cy.setCodemirrorContent('```mermaid\ngraph TD;\n A-->B;\n```') cy.setCodemirrorContent('```mermaid\ngraph TD;\n A-->B;\n```')
cy.getMarkdownBody().find('.mermaid').children().should('be.visible') cy.getMarkdownBody().findByCypressId('mermaid-frame').children().should('be.visible')
}) })
it('renders flowcharts', () => { it('renders flowcharts', () => {
cy.setCodemirrorContent('```flow\nst=>start: Start\ne=>end: End\nst->e\n```') cy.setCodemirrorContent('```flow\nst=>start: Start\ne=>end: End\nst->e\n```')
cy.getMarkdownBody().findById('flowchart').children().should('be.visible') cy.getMarkdownBody().findByCypressId('flowchart').children().should('be.visible')
}) })
it('renders abc scores', () => { it('renders abc scores', () => {
cy.setCodemirrorContent('```abc\nM:4/4\nK:G\n|:GABc dedB:|\n```') cy.setCodemirrorContent('```abc\nM:4/4\nK:G\n|:GABc dedB:|\n```')
cy.getMarkdownBody().findById('abcjs').children().should('be.visible') cy.getMarkdownBody().findByCypressId('abcjs').children().should('be.visible')
}) })
it('renders csv as table', () => { it('renders csv as table', () => {
cy.setCodemirrorContent('```csv delimiter=; header\na;b;c;d\n1;2;3;4\n```') cy.setCodemirrorContent('```csv delimiter=; header\na;b;c;d\n1;2;3;4\n```')
cy.getMarkdownBody().findById('csv-html-table').first().should('be.visible') cy.getMarkdownBody().findByCypressId('csv-html-table').first().should('be.visible')
}) })
it('renders plantuml', () => { it('renders plantuml', () => {

View file

@ -10,7 +10,7 @@ const title = 'This is a test title'
describe('Document Title', () => { describe('Document Title', () => {
beforeEach(() => { beforeEach(() => {
cy.visitTestEditor() cy.visitTestEditor()
cy.getById('view-mode-both').should('exist') cy.getByCypressId('view-mode-both').should('exist')
}) })
describe('title should be yaml metadata title', () => { describe('title should be yaml metadata title', () => {

View file

@ -7,18 +7,18 @@
describe('Editor mode from URL parameter is used', () => { describe('Editor mode from URL parameter is used', () => {
it('mode view', () => { it('mode view', () => {
cy.visitTestEditor('view') cy.visitTestEditor('view')
cy.get('.splitter.left').should('not.be.visible') cy.getByCypressId('splitter-left').should('not.be.visible')
cy.get('.splitter.right').should('be.visible') cy.getByCypressId('splitter-right').should('be.visible')
}) })
it('mode both', () => { it('mode both', () => {
cy.visitTestEditor('both') cy.visitTestEditor('both')
cy.get('.splitter.left').should('be.visible') cy.getByCypressId('splitter-left').should('be.visible')
cy.get('.splitter.separator').should('exist') cy.getByCypressId('splitter-separator').should('exist')
cy.get('.splitter.right').should('be.visible') cy.getByCypressId('splitter-right').should('be.visible')
}) })
it('mode edit', () => { it('mode edit', () => {
cy.visitTestEditor('edit') cy.visitTestEditor('edit')
cy.get('.splitter.left').should('be.visible') cy.getByCypressId('splitter-left').should('be.visible')
cy.get('.splitter.right').should('not.be.visible') cy.getByCypressId('splitter-right').should('not.be.visible')
}) })
}) })

View file

@ -14,8 +14,8 @@ describe('Export', () => {
}) })
it('Markdown', () => { it('Markdown', () => {
cy.getById('menu-export').click() cy.getByCypressId('menu-export').click()
cy.getById('menu-export-markdown').click() cy.getByCypressId('menu-export-markdown').click()
cy.get('a[download]') cy.get('a[download]')
.then( .then(
(anchor) => (anchor) =>

View file

@ -40,8 +40,8 @@ describe('File upload', () => {
) )
}) })
it('via button', () => { it('via button', () => {
cy.getById('editor-toolbar-upload-image-button').should('be.visible') cy.getByCypressId('editor-toolbar-upload-image-button').should('be.visible')
cy.getById('editor-toolbar-upload-image-input').attachFixture({ cy.getByCypressId('editor-toolbar-upload-image-input').attachFixture({
filePath: 'demo.png', filePath: 'demo.png',
mimeType: 'image/png' mimeType: 'image/png'
}) })
@ -86,8 +86,8 @@ describe('File upload', () => {
statusCode: 400 statusCode: 400
} }
) )
cy.getById('editor-toolbar-upload-image-button').should('be.visible') cy.getByCypressId('editor-toolbar-upload-image-button').should('be.visible')
cy.getById('editor-toolbar-upload-image-input').attachFixture({ cy.getByCypressId('editor-toolbar-upload-image-input').attachFixture({
filePath: 'demo.png', filePath: 'demo.png',
mimeType: 'image/png' mimeType: 'image/png'
}) })

View file

@ -10,7 +10,7 @@ describe('Help Dialog', () => {
}) })
it('ToDo-List', () => { it('ToDo-List', () => {
cy.getById('editor-help-button').click() cy.getByCypressId('editor-help-button').click()
cy.get('input[type="checkbox"]').should('exist').should('not.be.checked') cy.get('input[type="checkbox"]').should('exist').should('not.be.checked')
}) })
}) })

View file

@ -5,7 +5,7 @@
*/ */
const findHljsCodeBlock = () => { const findHljsCodeBlock = () => {
return cy.getMarkdownBody().find('.code-highlighter > code.hljs').should('be.visible') return cy.getMarkdownBody().findByCypressId('code-highlighter').should('be.visible')
} }
describe('Code', () => { describe('Code', () => {
@ -16,17 +16,18 @@ describe('Code', () => {
describe('with just the language', () => { describe('with just the language', () => {
it("doesn't show a gutter", () => { it("doesn't show a gutter", () => {
cy.setCodemirrorContent('```javascript \nlet x = 0\n```') cy.setCodemirrorContent('```javascript \nlet x = 0\n```')
findHljsCodeBlock().should('not.have.class', 'showGutter') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'false')
findHljsCodeBlock().find('.linenumber').should('not.be.visible') findHljsCodeBlock().findByCypressId('linenumber').should('not.be.visible')
}) })
describe('and line wrapping', () => { describe('and line wrapping', () => {
it("doesn't show a gutter", () => { it("doesn't show a gutter", () => {
cy.setCodemirrorContent('```javascript! \nlet x = 0\n```') cy.setCodemirrorContent('```javascript! \nlet x = 0\n```')
findHljsCodeBlock().should('not.have.class', 'showGutter').should('have.class', 'wrapLines') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'false')
findHljsCodeBlock().should('have.attr', 'data-cypress-wrapLines', 'true')
findHljsCodeBlock().find('.linenumber').should('not.be.visible') findHljsCodeBlock().findByCypressId('linenumber').should('not.be.visible')
}) })
}) })
}) })
@ -34,17 +35,18 @@ describe('Code', () => {
describe('with the language and show gutter', () => { describe('with the language and show gutter', () => {
it('shows the correct line number', () => { it('shows the correct line number', () => {
cy.setCodemirrorContent('```javascript= \nlet x = 0\n```') cy.setCodemirrorContent('```javascript= \nlet x = 0\n```')
findHljsCodeBlock().should('have.class', 'showGutter') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
findHljsCodeBlock().find('.linenumber').should('be.visible').text().should('eq', '1') findHljsCodeBlock().findByCypressId('linenumber').should('be.visible').text().should('eq', '1')
}) })
describe('and line wrapping', () => { describe('and line wrapping', () => {
it('shows the correct line number', () => { it('shows the correct line number', () => {
cy.setCodemirrorContent('```javascript=! \nlet x = 0\n```') cy.setCodemirrorContent('```javascript=! \nlet x = 0\n```')
findHljsCodeBlock().should('have.class', 'showGutter').should('have.class', 'wrapLines') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
findHljsCodeBlock().should('have.attr', 'data-cypress-wrapLines', 'true')
findHljsCodeBlock().find('.linenumber').should('be.visible').text().should('eq', '1') findHljsCodeBlock().findByCypressId('linenumber').should('be.visible').text().should('eq', '1')
}) })
}) })
}) })
@ -52,45 +54,40 @@ describe('Code', () => {
describe('with the language, show gutter with a start number', () => { describe('with the language, show gutter with a start number', () => {
it('shows the correct line number', () => { it('shows the correct line number', () => {
cy.setCodemirrorContent('```javascript=100 \nlet x = 0\n```') cy.setCodemirrorContent('```javascript=100 \nlet x = 0\n```')
findHljsCodeBlock().should('have.class', 'showGutter') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
findHljsCodeBlock().find('.linenumber').should('be.visible').text().should('eq', '100') findHljsCodeBlock().findByCypressId('linenumber').should('be.visible').text().should('eq', '100')
}) })
it('shows the correct line number and continues in another codeblock', () => { it('shows the correct line number and continues in another codeblock', () => {
cy.setCodemirrorContent('```javascript=100 \nlet x = 0\nlet y = 1\n```\n\n```javascript=+\nlet y = 2\n```\n') cy.setCodemirrorContent('```javascript=100 \nlet x = 0\nlet y = 1\n```\n\n```javascript=+\nlet y = 2\n```\n')
findHljsCodeBlock() findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
.should('have.class', 'showGutter') findHljsCodeBlock().first().findByCypressId('linenumber').first().should('be.visible').text().should('eq', '100')
.first() findHljsCodeBlock().first().findByCypressId('linenumber').last().should('be.visible').text().should('eq', '101')
.find('.linenumber') findHljsCodeBlock().last().findByCypressId('linenumber').first().should('be.visible').text().should('eq', '102')
.first()
.should('be.visible')
.text()
.should('eq', '100')
findHljsCodeBlock().first().find('.linenumber').last().should('be.visible').text().should('eq', '101')
findHljsCodeBlock().last().find('.linenumber').first().should('be.visible').text().should('eq', '102')
}) })
describe('and line wrapping', () => { describe('and line wrapping', () => {
it('shows the correct line number', () => { it('shows the correct line number', () => {
cy.setCodemirrorContent('```javascript=100! \nlet x = 0\n```') cy.setCodemirrorContent('```javascript=100! \nlet x = 0\n```')
findHljsCodeBlock().should('have.class', 'showGutter').should('have.class', 'wrapLines') findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
findHljsCodeBlock().find('.linenumber').should('be.visible').text().should('eq', '100') findHljsCodeBlock().should('have.attr', 'data-cypress-wrapLines', 'true')
findHljsCodeBlock().findByCypressId('linenumber').should('be.visible').text().should('eq', '100')
}) })
it('shows the correct line number and continues in another codeblock', () => { it('shows the correct line number and continues in another codeblock', () => {
cy.setCodemirrorContent('```javascript=100! \nlet x = 0\nlet y = 1\n```\n\n```javascript=+\nlet y = 2\n```\n') cy.setCodemirrorContent('```javascript=100! \nlet x = 0\nlet y = 1\n```\n\n```javascript=+\nlet y = 2\n```\n')
findHljsCodeBlock().should('have.attr', 'data-cypress-showgutter', 'true')
findHljsCodeBlock().should('have.attr', 'data-cypress-wrapLines', 'true')
findHljsCodeBlock() findHljsCodeBlock()
.should('have.class', 'showGutter')
.should('have.class', 'wrapLines')
.first() .first()
.find('.linenumber') .findByCypressId('linenumber')
.first() .first()
.should('be.visible') .should('be.visible')
.text() .text()
.should('eq', '100') .should('eq', '100')
findHljsCodeBlock().first().find('.linenumber').last().should('be.visible').text().should('eq', '101') findHljsCodeBlock().first().findByCypressId('linenumber').last().should('be.visible').text().should('eq', '101')
findHljsCodeBlock().last().find('.linenumber').first().should('be.visible').text().should('eq', '102') findHljsCodeBlock().last().findByCypressId('linenumber').first().should('be.visible').text().should('eq', '102')
}) })
}) })
}) })
@ -98,7 +95,7 @@ describe('Code', () => {
it('has a working copy button', () => { it('has a working copy button', () => {
cy.setCodemirrorContent('```javascript \nlet x = 0\n```') cy.setCodemirrorContent('```javascript \nlet x = 0\n```')
cy.getById('documentIframe').then((element: JQuery<HTMLElement>) => { cy.getByCypressId('documentIframe').then((element: JQuery<HTMLElement>) => {
const frame = element.get(0) as HTMLIFrameElement const frame = element.get(0) as HTMLIFrameElement
if (frame === null || frame.contentWindow === null) { if (frame === null || frame.contentWindow === null) {
return cy.wrap(null) return cy.wrap(null)
@ -107,7 +104,7 @@ describe('Code', () => {
cy.spy(frame.contentWindow.navigator.clipboard, 'writeText').as('copy') cy.spy(frame.contentWindow.navigator.clipboard, 'writeText').as('copy')
}) })
cy.getIframeBody().findById('copy-code-button').click() cy.getIframeBody().findByCypressId('copy-code-button').click()
cy.get('@copy').should('be.calledWithExactly', 'let x = 0\n') cy.get('@copy').should('be.calledWithExactly', 'let x = 0\n')
}) })

View file

@ -11,12 +11,12 @@ describe('History', () => {
}) })
it('Cards', () => { it('Cards', () => {
cy.getById('history-card').should('be.visible') cy.getByCypressId('history-card').should('be.visible')
}) })
it('Table', () => { it('Table', () => {
cy.getById('history-mode-table').click() cy.getByCypressId('history-mode-table').click()
cy.getById('history-table').should('be.visible') cy.getByCypressId('history-table').should('be.visible')
}) })
}) })
@ -39,13 +39,13 @@ describe('History', () => {
}) })
it('in table view', () => { it('in table view', () => {
cy.getById('history-mode-table').click() cy.getByCypressId('history-mode-table').click()
cy.getById('history-table').should('be.visible') cy.getByCypressId('history-table').should('be.visible')
cy.getById('history-entry-title').contains('Features') cy.getByCypressId('history-entry-title').contains('Features')
}) })
it('in cards view', () => { it('in cards view', () => {
cy.getById('history-entry-title').contains('Features') cy.getByCypressId('history-entry-title').contains('Features')
}) })
}) })
describe('is untitled when not empty', () => { describe('is untitled when not empty', () => {
@ -66,13 +66,13 @@ describe('History', () => {
}) })
it('in table view', () => { it('in table view', () => {
cy.getById('history-mode-table').click() cy.getByCypressId('history-mode-table').click()
cy.getById('history-table').should('be.visible') cy.getByCypressId('history-table').should('be.visible')
cy.getById('history-entry-title').contains('Untitled') cy.getByCypressId('history-entry-title').contains('Untitled')
}) })
it('in cards view', () => { it('in cards view', () => {
cy.getById('history-entry-title').contains('Untitled') cy.getByCypressId('history-entry-title').contains('Untitled')
}) })
}) })
}) })
@ -90,17 +90,17 @@ describe('History', () => {
}) })
it('Cards', () => { it('Cards', () => {
cy.getById('history-card').should('be.visible') cy.getByCypressId('history-card').should('be.visible')
cy.getById('history-entry-pin-button').first().as('pin-button') cy.getByCypressId('history-entry-pin-button').first().as('pin-button')
cy.get('@pin-button').should('have.class', 'pinned').click() cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'true').click()
cy.get('@pin-button').should('not.have.class', 'pinned') cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'false')
}) })
it('Table', () => { it('Table', () => {
cy.getById('history-mode-table').click() cy.getByCypressId('history-mode-table').click()
cy.getById('history-entry-pin-button').first().as('pin-button') cy.getByCypressId('history-entry-pin-button').first().as('pin-button')
cy.get('@pin-button').should('have.class', 'pinned').click() cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'true').click()
cy.get('@pin-button').should('not.have.class', 'pinned') cy.get('@pin-button').should('have.attr', 'data-cypress-pinned', 'false')
}) })
}) })
@ -112,15 +112,15 @@ describe('History', () => {
}) })
it('Cards', () => { it('Cards', () => {
cy.getById('history-card').should('be.visible') cy.getByCypressId('history-card').should('be.visible')
cy.getById('history-entry-pin-button').first().click() cy.getByCypressId('history-entry-pin-button').first().click()
cy.getById('notification-toast').should('be.visible') cy.getByCypressId('notification-toast').should('be.visible')
}) })
it('Table', () => { it('Table', () => {
cy.getById('history-mode-table').click() cy.getByCypressId('history-mode-table').click()
cy.getById('history-entry-pin-button').first().click() cy.getByCypressId('history-entry-pin-button').first().click()
cy.getById('notification-toast').should('be.visible') cy.getByCypressId('notification-toast').should('be.visible')
}) })
}) })
}) })
@ -136,37 +136,37 @@ describe('History', () => {
}) })
it('works with valid file', () => { it('works with valid file', () => {
cy.getById('import-history-file-button').should('be.visible') cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getById('import-history-file-input').attachFixture({ cy.getByCypressId('import-history-file-input').attachFixture({
filePath: 'history.json', filePath: 'history.json',
mimeType: 'application/json' mimeType: 'application/json'
}) })
cy.getById('history-entry-title').should('have.length', 1).contains('cy-Test') cy.getByCypressId('history-entry-title').should('have.length', 1).contains('cy-Test')
}) })
it('fails on invalid file', () => { it('fails on invalid file', () => {
cy.getById('import-history-file-button').should('be.visible') cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getById('import-history-file-input').attachFixture({ cy.getByCypressId('import-history-file-input').attachFixture({
filePath: 'invalid-history.txt', filePath: 'invalid-history.txt',
mimeType: 'text/plain' mimeType: 'text/plain'
}) })
cy.getById('notification-toast').should('be.visible') cy.getByCypressId('notification-toast').should('be.visible')
}) })
it('works when selecting two files with the same name', () => { it('works when selecting two files with the same name', () => {
cy.getById('import-history-file-button').should('be.visible') cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getById('import-history-file-input').attachFixture({ cy.getByCypressId('import-history-file-input').attachFixture({
filePath: 'history.json', filePath: 'history.json',
mimeType: 'application/json' mimeType: 'application/json'
}) })
cy.getById('history-entry-title').should('have.length', 1).contains('cy-Test') cy.getByCypressId('history-entry-title').should('have.length', 1).contains('cy-Test')
cy.getById('import-history-file-button').should('be.visible') cy.getByCypressId('import-history-file-button').should('be.visible')
cy.getById('import-history-file-input').attachFixture({ cy.getByCypressId('import-history-file-input').attachFixture({
filePath: 'history-2.json', filePath: 'history-2.json',
fileName: 'history.json', fileName: 'history.json',
mimeType: 'application/json' mimeType: 'application/json'
}) })
cy.getById('history-entry-title').should('have.length', 2).contains('cy-Test2') cy.getByCypressId('history-entry-title').should('have.length', 2).contains('cy-Test2')
}) })
}) })
}) })

View file

@ -11,7 +11,7 @@ describe('Iframe capsule', () => {
it('shows a clickable click shield instead of the iframe', () => { it('shows a clickable click shield instead of the iframe', () => {
cy.setCodemirrorContent('<iframe src="https://example.org"></iframe>') cy.setCodemirrorContent('<iframe src="https://example.org"></iframe>')
cy.getMarkdownBody().findById('iframe-capsule-click-shield').should('exist').click() cy.getMarkdownBody().findByCypressId('iframe-capsule-click-shield').should('exist').click()
cy.getMarkdownBody().find('iframe').should('exist').should('have.attr', 'src', 'https://example.org') cy.getMarkdownBody().find('iframe').should('exist').should('have.attr', 'src', 'https://example.org')
}) })
}) })

View file

@ -10,9 +10,9 @@ describe('Import markdown file', () => {
}) })
it('import on blank note', () => { it('import on blank note', () => {
cy.getById('menu-import').click() cy.getByCypressId('menu-import').click()
cy.getById('menu-import-markdown-button').should('be.visible') cy.getByCypressId('menu-import-markdown-button').should('be.visible')
cy.getById('menu-import-markdown-input').attachFixture({ cy.getByCypressId('menu-import-markdown-input').attachFixture({
filePath: 'import.md', filePath: 'import.md',
mimeType: 'text/markdown' mimeType: 'text/markdown'
}) })
@ -25,9 +25,9 @@ describe('Import markdown file', () => {
it('import on note with content', () => { it('import on note with content', () => {
cy.setCodemirrorContent('test\nabc') cy.setCodemirrorContent('test\nabc')
cy.getById('menu-import').click() cy.getByCypressId('menu-import').click()
cy.getById('menu-import-markdown-button').should('be.visible') cy.getByCypressId('menu-import-markdown-button').should('be.visible')
cy.getById('menu-import-markdown-input').attachFixture({ cy.getByCypressId('menu-import-markdown-input').attachFixture({
filePath: 'import.md', filePath: 'import.md',
mimeType: 'text/markdown' mimeType: 'text/markdown'
}) })

View file

@ -22,39 +22,39 @@ describe('Intro page', () => {
}) })
cy.visit('/') cy.visit('/')
cy.getById('documentIframe').should('not.exist') cy.getByCypressId('documentIframe').should('not.exist')
}) })
}) })
describe('features button', () => { describe('features button', () => {
it('is hidden when logged in', () => { it('is hidden when logged in', () => {
cy.getById('features-button').should('not.exist') cy.getByCypressId('features-button').should('not.exist')
}) })
it('is visible when logged out', () => { it('is visible when logged out', () => {
cy.logout() cy.logout()
cy.getById('features-button').should('exist') cy.getByCypressId('features-button').should('exist')
}) })
}) })
describe('sign in button', () => { describe('sign in button', () => {
it('is hidden when logged in', () => { it('is hidden when logged in', () => {
cy.getById('sign-in-button').should('not.exist') cy.getByCypressId('sign-in-button').should('not.exist')
}) })
it('is visible when logged out', () => { it('is visible when logged out', () => {
cy.logout() cy.logout()
cy.getById('sign-in-button').should('exist') cy.getByCypressId('sign-in-button').should('exist')
}) })
}) })
describe('version dialog', () => { describe('version dialog', () => {
it('can be opened and closed', () => { it('can be opened and closed', () => {
cy.getById('version-modal').should('not.exist') cy.getByCypressId('version-modal').should('not.exist')
cy.getById('show-version-modal').click() cy.getByCypressId('show-version-modal').click()
cy.getById('version-modal').should('be.visible') cy.getByCypressId('version-modal').should('be.visible')
cy.getById('version-modal').find('.modal-header .close').click() cy.getByCypressId('version-modal').find('.modal-header .close').click()
cy.getById('version-modal').should('not.exist') cy.getByCypressId('version-modal').should('not.exist')
}) })
}) })
}) })

View file

@ -12,7 +12,7 @@ describe('Languages', () => {
}) })
it('all languages are available', () => { it('all languages are available', () => {
cy.getById('language-picker').find('option').as('languages') cy.getByCypressId('language-picker').find('option').as('languages')
cy.get('@languages').should('have.length', 28) cy.get('@languages').should('have.length', 28)
languages.forEach((language) => { languages.forEach((language) => {
cy.get('@languages').contains(language) cy.get('@languages').contains(language)
@ -20,9 +20,9 @@ describe('Languages', () => {
}) })
it('language changes affect the UI', () => { it('language changes affect the UI', () => {
cy.getById('language-picker').select('English') cy.getByCypressId('language-picker').select('English')
cy.getById('new-note-button').find('span').contains('New note') cy.getByCypressId('new-note-button').find('span').contains('New note')
cy.getById('language-picker').select('Deutsch') cy.getByCypressId('language-picker').select('Deutsch')
cy.getById('new-note-button').find('span').contains('Neue Notiz') cy.getByCypressId('new-note-button').find('span').contains('Neue Notiz')
}) })
}) })

View file

@ -12,9 +12,9 @@ describe('Links Intro', () => {
}) })
it('History', () => { it('History', () => {
cy.getById('navLinkHistory').click() cy.getByCypressId('navLinkHistory').click()
cy.url().should('include', '/history') cy.url().should('include', '/history')
cy.getById('navLinkIntro').click() cy.getByCypressId('navLinkIntro').click()
cy.url().should('include', '/intro') cy.url().should('include', '/intro')
}) })
@ -24,29 +24,29 @@ describe('Links Intro', () => {
}) })
it('New guest note', () => { it('New guest note', () => {
cy.getById('new-guest-note-button').click() cy.getByCypressId('new-guest-note-button').click()
cy.url().should('include', '/new') cy.url().should('include', '/new')
}) })
}) })
describe('Menu Buttons logged in', () => { describe('Menu Buttons logged in', () => {
it('New note', () => { it('New note', () => {
cy.getById('new-note-button').click() cy.getByCypressId('new-note-button').click()
cy.url().should('include', '/new') cy.url().should('include', '/new')
}) })
describe('User Menu', () => { describe('User Menu', () => {
beforeEach(() => { beforeEach(() => {
cy.getById('user-dropdown').click() cy.getByCypressId('user-dropdown').click()
}) })
it('Features', () => { it('Features', () => {
cy.getById('user-dropdown-features-button').click() cy.getByCypressId('user-dropdown-features-button').click()
cy.url().should('include', '/features') cy.url().should('include', '/features')
}) })
it('Profile', () => { it('Profile', () => {
cy.getById('user-dropdown-profile-button').click() cy.getByCypressId('user-dropdown-profile-button').click()
cy.url().should('include', '/profile') cy.url().should('include', '/profile')
}) })
}) })

View file

@ -13,14 +13,14 @@ describe('Link gets replaced with embedding: ', () => {
it('GitHub Gist', () => { it('GitHub Gist', () => {
cy.setCodemirrorContent('https://gist.github.com/schacon/1') cy.setCodemirrorContent('https://gist.github.com/schacon/1')
cy.getMarkdownBody().findById('click-shield-gist').find('.preview-background').parent().click() cy.getMarkdownBody().findByCypressId('click-shield-gist').find('.preview-background').parent().click()
cy.getMarkdownBody().findById('gh-gist').should('be.visible') cy.getMarkdownBody().findByCypressId('gh-gist').should('be.visible')
}) })
it('YouTube', () => { it('YouTube', () => {
cy.setCodemirrorContent('https://www.youtube.com/watch?v=YE7VzlLtp-4') cy.setCodemirrorContent('https://www.youtube.com/watch?v=YE7VzlLtp-4')
cy.getMarkdownBody() cy.getMarkdownBody()
.findById('click-shield-youtube') .findByCypressId('click-shield-youtube')
.find('.preview-background') .find('.preview-background')
.should('have.attr', 'src', 'https://i.ytimg.com/vi/YE7VzlLtp-4/maxresdefault.jpg') .should('have.attr', 'src', 'https://i.ytimg.com/vi/YE7VzlLtp-4/maxresdefault.jpg')
.parent() .parent()
@ -46,7 +46,7 @@ describe('Link gets replaced with embedding: ', () => {
) )
cy.setCodemirrorContent('https://vimeo.com/23237102') cy.setCodemirrorContent('https://vimeo.com/23237102')
cy.getMarkdownBody() cy.getMarkdownBody()
.findById('click-shield-vimeo') .findByCypressId('click-shield-vimeo')
.find('.preview-background') .find('.preview-background')
.should('have.attr', 'src', 'https://i.vimeocdn.com/video/503631401_640.jpg') .should('have.attr', 'src', 'https://i.vimeocdn.com/video/503631401_640.jpg')
.parent() .parent()
@ -57,7 +57,7 @@ describe('Link gets replaced with embedding: ', () => {
it('Asciinema', () => { it('Asciinema', () => {
cy.setCodemirrorContent('https://asciinema.org/a/117928') cy.setCodemirrorContent('https://asciinema.org/a/117928')
cy.getMarkdownBody() cy.getMarkdownBody()
.findById('click-shield-asciinema') .findByCypressId('click-shield-asciinema')
.find('.preview-background') .find('.preview-background')
.should('have.attr', 'src', 'https://asciinema.org/a/117928.png') .should('have.attr', 'src', 'https://asciinema.org/a/117928.png')
.parent() .parent()

View file

@ -14,21 +14,21 @@ describe('The status bar text length info', () => {
}) })
it('shows the maximal length of the document as number of available characters in the tooltip', () => { it('shows the maximal length of the document as number of available characters in the tooltip', () => {
cy.getById('remainingCharacters').attribute('title').should('contain', ' 200 ') cy.getByCypressId('remainingCharacters').attribute('title').should('contain', ' 200 ')
}) })
it('color is set to "warning" on <= 100 characters remaining', () => { it('color is set to "warning" on <= 100 characters remaining', () => {
cy.setCodemirrorContent(warningTestContent) cy.setCodemirrorContent(warningTestContent)
cy.getById('remainingCharacters').should('have.class', 'text-warning') cy.getByCypressId('remainingCharacters').should('have.class', 'text-warning')
}) })
it('color is set to danger on <= 0 characters remaining', () => { it('color is set to danger on <= 0 characters remaining', () => {
cy.setCodemirrorContent(dangerTestContent) cy.setCodemirrorContent(dangerTestContent)
cy.getById('remainingCharacters').should('have.class', 'text-danger') cy.getByCypressId('remainingCharacters').should('have.class', 'text-danger')
}) })
it('opens a modal', () => { it('opens a modal', () => {
cy.setCodemirrorContent(tooMuchTestContent) cy.setCodemirrorContent(tooMuchTestContent)
cy.getById('limitReachedModal').should('be.visible') cy.getByCypressId('limitReachedModal').should('be.visible')
}) })
}) })

View file

@ -29,63 +29,63 @@ describe('Motd', () => {
it('shows the correct alert Motd text', () => { it('shows the correct alert Motd text', () => {
mockExistingMotd() mockExistingMotd()
cy.visit('/') cy.visit('/')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
}) })
it('can be dismissed', () => { it('can be dismissed', () => {
mockExistingMotd() mockExistingMotd()
cy.visit('/') cy.visit('/')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
cy.getById('motd-dismiss') cy.getByCypressId('motd-dismiss')
.click() .click()
.then(() => { .then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED) expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
}) })
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
}) })
it("won't show again after dismiss and reload", () => { it("won't show again after dismiss and reload", () => {
mockExistingMotd() mockExistingMotd()
cy.visit('/') cy.visit('/')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
cy.getById('motd-dismiss') cy.getByCypressId('motd-dismiss')
.click() .click()
.then(() => { .then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED) expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
}) })
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
cy.reload() cy.reload()
cy.get('main').should('exist') cy.get('main').should('exist')
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
}) })
it('will show again after reload without dismiss', () => { it('will show again after reload without dismiss', () => {
mockExistingMotd() mockExistingMotd()
cy.visit('/') cy.visit('/')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
cy.reload() cy.reload()
cy.get('main').should('exist') cy.get('main').should('exist')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
}) })
it("won't show again after dismiss and page navigation", () => { it("won't show again after dismiss and page navigation", () => {
mockExistingMotd() mockExistingMotd()
cy.visit('/') cy.visit('/')
cy.getById('motd').contains(motdMockContent) cy.getByCypressId('motd').contains(motdMockContent)
cy.getById('motd-dismiss') cy.getByCypressId('motd-dismiss')
.click() .click()
.then(() => { .then(() => {
expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED) expect(localStorage.getItem(MOTD_LOCAL_STORAGE_KEY)).to.equal(MOCK_LAST_MODIFIED)
}) })
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
cy.getById('navLinkHistory').click() cy.getByCypressId('navLinkHistory').click()
cy.get('main').should('exist') cy.get('main').should('exist')
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
}) })
it("won't show if no file exists", () => { it("won't show if no file exists", () => {
cy.visit('/') cy.visit('/')
cy.get('main').should('exist') cy.get('main').should('exist')
cy.getById('motd').should('not.exist') cy.getByCypressId('motd').should('not.exist')
}) })
}) })

View file

@ -53,22 +53,22 @@ describe('profile page', () => {
describe('access tokens', () => { describe('access tokens', () => {
it('list existing tokens', () => { it('list existing tokens', () => {
cy.getById('access-token-label').contains('cypress-App') cy.getByCypressId('access-token-label').contains('cypress-App')
}) })
it('delete token', () => { it('delete token', () => {
cy.getById('access-token-delete-button').click() cy.getByCypressId('access-token-delete-button').click()
cy.getById('access-token-modal-delete').as('deletion-modal') cy.getByCypressId('access-token-modal-delete').as('deletion-modal')
cy.get('@deletion-modal').should('be.visible').find('.modal-footer .btn-danger').click() cy.get('@deletion-modal').should('be.visible').find('.modal-footer .btn-danger').click()
cy.get('@deletion-modal').should('not.exist') cy.get('@deletion-modal').should('not.exist')
}) })
it('add token', () => { it('add token', () => {
cy.getById('access-token-add-button').should('be.disabled') cy.getByCypressId('access-token-add-button').should('be.disabled')
cy.getById('access-token-add-input-label').type('cypress') cy.getByCypressId('access-token-add-input-label').type('cypress')
cy.getById('access-token-modal-add').should('not.exist') cy.getByCypressId('access-token-modal-add').should('not.exist')
cy.getById('access-token-add-button').should('not.be.disabled').click() cy.getByCypressId('access-token-add-button').should('not.be.disabled').click()
cy.getById('access-token-modal-add') cy.getByCypressId('access-token-modal-add')
.should('be.visible') .should('be.visible')
.find('input[readonly]') .find('input[readonly]')
.should('have.value', 'c-y-p-r-e-s-s') .should('have.value', 'c-y-p-r-e-s-s')

View file

@ -35,7 +35,7 @@ describe('Short code gets replaced or rendered: ', () => {
describe('youtube', () => { describe('youtube', () => {
it('renders click-shield', () => { it('renders click-shield', () => {
cy.setCodemirrorContent(`{%youtube YE7VzlLtp-4 %}`) cy.setCodemirrorContent(`{%youtube YE7VzlLtp-4 %}`)
cy.getMarkdownBody().findById('click-shield-youtube') cy.getMarkdownBody().findByCypressId('click-shield-youtube')
}) })
}) })
}) })

View file

@ -34,7 +34,7 @@ const initLoggedOutTestWithCustomAuthProviders = (
describe('When logged-in, ', () => { describe('When logged-in, ', () => {
it('sign-in button is hidden', () => { it('sign-in button is hidden', () => {
cy.visit('/') cy.visit('/')
cy.getById('sign-in-button').should('not.exist') cy.getByCypressId('sign-in-button').should('not.exist')
}) })
}) })
@ -42,7 +42,7 @@ describe('When logged-out ', () => {
describe('and no auth-provider is enabled, ', () => { describe('and no auth-provider is enabled, ', () => {
it('sign-in button is hidden', () => { it('sign-in button is hidden', () => {
initLoggedOutTestWithCustomAuthProviders(cy, {}) initLoggedOutTestWithCustomAuthProviders(cy, {})
cy.getById('sign-in-button').should('not.exist') cy.getByCypressId('sign-in-button').should('not.exist')
}) })
}) })
@ -51,14 +51,14 @@ describe('When logged-out ', () => {
initLoggedOutTestWithCustomAuthProviders(cy, { initLoggedOutTestWithCustomAuthProviders(cy, {
local: true local: true
}) })
cy.getById('sign-in-button').should('be.visible').should('have.attr', 'href', '/login') cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
}) })
it('sign-in button points to login route: ldap', () => { it('sign-in button points to login route: ldap', () => {
initLoggedOutTestWithCustomAuthProviders(cy, { initLoggedOutTestWithCustomAuthProviders(cy, {
ldap: true ldap: true
}) })
cy.getById('sign-in-button').should('be.visible').should('have.attr', 'href', '/login') cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
}) })
}) })
@ -67,7 +67,7 @@ describe('When logged-out ', () => {
initLoggedOutTestWithCustomAuthProviders(cy, { initLoggedOutTestWithCustomAuthProviders(cy, {
saml: true saml: true
}) })
cy.getById('sign-in-button') cy.getByCypressId('sign-in-button')
.should('be.visible') .should('be.visible')
// The absolute URL is used because it is defined as API base URL absolute. // The absolute URL is used because it is defined as API base URL absolute.
.should('have.attr', 'href', '/mock-backend/auth/saml') .should('have.attr', 'href', '/mock-backend/auth/saml')
@ -80,7 +80,7 @@ describe('When logged-out ', () => {
saml: true, saml: true,
github: true github: true
}) })
cy.getById('sign-in-button').should('be.visible').should('have.attr', 'href', '/login') cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
}) })
}) })
@ -90,7 +90,7 @@ describe('When logged-out ', () => {
saml: true, saml: true,
local: true local: true
}) })
cy.getById('sign-in-button').should('be.visible').should('have.attr', 'href', '/login') cy.getByCypressId('sign-in-button').should('be.visible').should('have.attr', 'href', '/login')
}) })
}) })
}) })

View file

@ -10,33 +10,33 @@ describe('Split view', () => {
}) })
it('can show both panes', () => { it('can show both panes', () => {
cy.getById('view-mode-both').click() cy.getByCypressId('view-mode-both').click()
cy.get('.splitter.left').should('be.visible') cy.getByCypressId('splitter-left').should('be.visible')
cy.get('.splitter.right').should('be.visible') cy.getByCypressId('splitter-right').should('be.visible')
}) })
it('can show only preview pane', () => { it('can show only preview pane', () => {
cy.getById('view-mode-preview').click() cy.getByCypressId('view-mode-preview').click()
cy.get('.splitter.left').should('be.not.visible') cy.getByCypressId('splitter-left').should('be.not.visible')
cy.get('.splitter.right').should('be.visible') cy.getByCypressId('splitter-right').should('be.visible')
}) })
it('can show only editor pane', () => { it('can show only editor pane', () => {
cy.getById('view-mode-editor').click() cy.getByCypressId('view-mode-editor').click()
cy.get('.splitter.left').should('be.visible') cy.getByCypressId('splitter-left').should('be.visible')
cy.get('.splitter.right').should('be.not.visible') cy.getByCypressId('splitter-right').should('be.not.visible')
}) })
it('can change the split by dragging', () => { it('can change the split by dragging', () => {
cy.get('.splitter.left').then((leftPanebefore) => { cy.getByCypressId('splitter-left').then((leftPanebefore) => {
const widthBefore = leftPanebefore.outerWidth() const widthBefore = leftPanebefore.outerWidth()
cy.getById('view-mode-both').click() cy.getByCypressId('view-mode-both').click()
cy.get('.split-divider').should('be.visible').trigger('mousedown', { buttons: 1 }) cy.getByCypressId('split-divider').should('be.visible').trigger('mousedown', { buttons: 1 })
cy.document().trigger('mousemove', { buttons: 1, pageX: 0, pageY: 0 }) cy.document().trigger('mousemove', { buttons: 1, pageX: 0, pageY: 0 })
cy.get('.split-divider').trigger('mouseup') cy.getByCypressId('split-divider').trigger('mouseup')
cy.get('.splitter.left').should('not.eq', widthBefore) cy.getByCypressId('splitter-left').should('not.eq', widthBefore)
}) })
}) })
}) })

View file

@ -26,17 +26,17 @@ describe('Toolbar Buttons', () => {
}) })
it('should format as bold', () => { it('should format as bold', () => {
cy.getById('format-bold').click() cy.getByCypressId('format-bold').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `**${testText}**`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `**${testText}**`)
}) })
it('should format as italic', () => { it('should format as italic', () => {
cy.getById('format-italic').click() cy.getByCypressId('format-italic').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `*${testText}*`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `*${testText}*`)
}) })
it('should format as underline', () => { it('should format as underline', () => {
cy.getById('format-underline').click() cy.getByCypressId('format-underline').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `++${testText}++`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `++${testText}++`)
}) })
@ -46,17 +46,17 @@ describe('Toolbar Buttons', () => {
}) })
it('should format as subscript', () => { it('should format as subscript', () => {
cy.getById('format-subscript').click() cy.getByCypressId('format-subscript').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `~${testText}~`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `~${testText}~`)
}) })
it('should format as superscript', () => { it('should format as superscript', () => {
cy.getById('format-superscript').click() cy.getByCypressId('format-superscript').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `^${testText}^`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `^${testText}^`)
}) })
it('should format the line as code block', () => { it('should format the line as code block', () => {
cy.getById('format-code-block').click() cy.getByCypressId('format-code-block').click()
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```') cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```')
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', testText) cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', testText)
cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should( cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should(
@ -66,65 +66,65 @@ describe('Toolbar Buttons', () => {
}) })
it('should format links', () => { it('should format links', () => {
cy.getById('format-link').click() cy.getByCypressId('format-link').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `[${testText}](https://)`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `[${testText}](https://)`)
}) })
it('should format as image', () => { it('should format as image', () => {
cy.getById('format-image').click() cy.getByCypressId('format-image').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `![${testText}](https://)`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `![${testText}](https://)`)
}) })
}) })
it('should format line as heading', () => { it('should format line as heading', () => {
cy.getById('format-heading').click() cy.getByCypressId('format-heading').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `# ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `# ${testText}`)
cy.get('.fa-header').click() cy.get('.fa-header').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `## ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `## ${testText}`)
}) })
it('should format the line as code', () => { it('should format the line as code', () => {
cy.getById('format-code-block').click() cy.getByCypressId('format-code-block').click()
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```') cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```')
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', testText) cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', testText)
cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should('have.text', '```') cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should('have.text', '```')
}) })
it('should add a quote', () => { it('should add a quote', () => {
cy.getById('format-block-quote').click() cy.getByCypressId('format-block-quote').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `> ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `> ${testText}`)
cy.getById('format-block-quote').click() cy.getByCypressId('format-block-quote').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `> > ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `> > ${testText}`)
}) })
it('should format as unordered list', () => { it('should format as unordered list', () => {
cy.getById('format-unordered-list').click() cy.getByCypressId('format-unordered-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- ${testText}`)
cy.getById('format-unordered-list').click() cy.getByCypressId('format-unordered-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- - ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- - ${testText}`)
}) })
it('should format as ordered list', () => { it('should format as ordered list', () => {
cy.getById('format-ordered-list').click() cy.getByCypressId('format-ordered-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `1. ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `1. ${testText}`)
cy.getById('format-ordered-list').click() cy.getByCypressId('format-ordered-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `1. 1. ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `1. 1. ${testText}`)
}) })
it('should format as check list', () => { it('should format as check list', () => {
cy.getById('format-check-list').click() cy.getByCypressId('format-check-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- [ ] ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- [ ] ${testText}`)
cy.getById('format-check-list').click() cy.getByCypressId('format-check-list').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- [ ] - [ ] ${testText}`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `- [ ] - [ ] ${testText}`)
}) })
it('should insert links', () => { it('should insert links', () => {
cy.getById('format-link').click() cy.getByCypressId('format-link').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `${testText}[](https://)`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `${testText}[](https://)`)
}) })
it('should insert an empty image link', () => { it('should insert an empty image link', () => {
cy.getById('format-image').click() cy.getByCypressId('format-image').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `${testText}![](https://)`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `${testText}![](https://)`)
}) })
}) })
@ -137,30 +137,30 @@ describe('Toolbar Buttons', () => {
}) })
it('should format as link', () => { it('should format as link', () => {
cy.getById('format-link').click() cy.getByCypressId('format-link').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `[](${testLink})`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `[](${testLink})`)
}) })
it('should format as image', () => { it('should format as image', () => {
cy.getById('format-image').click() cy.getByCypressId('format-image').click()
cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `![](${testLink})`) cy.get('.CodeMirror-activeline > .CodeMirror-line > span').should('have.text', `![](${testLink})`)
}) })
}) })
describe('for no text', () => { describe('for no text', () => {
it('should add an empty code block', () => { it('should add an empty code block', () => {
cy.getById('format-code-block').click() cy.getByCypressId('format-code-block').click()
cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```') cy.get('.CodeMirror-code > div:nth-of-type(1) > .CodeMirror-line > span > span').should('have.text', '```')
cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should('have.text', '```') cy.get('.CodeMirror-code > div.CodeMirror-activeline > .CodeMirror-line > span span').should('have.text', '```')
}) })
it('should insert lines', () => { it('should insert lines', () => {
cy.getById('format-add-line').click() cy.getByCypressId('format-add-line').click()
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', '----') cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', '----')
}) })
it('should add a collapsable block', () => { it('should add a collapsable block', () => {
cy.getById('format-collapsable-block').click() cy.getByCypressId('format-collapsable-block').click()
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should( cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should(
'have.text', 'have.text',
':::spoiler Toggle label' ':::spoiler Toggle label'
@ -168,36 +168,34 @@ describe('Toolbar Buttons', () => {
}) })
it('should add a comment', () => { it('should add a comment', () => {
cy.getById('format-add-comment').click() cy.getByCypressId('format-add-comment').click()
cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', '> []') cy.get('.CodeMirror-code > div:nth-of-type(2) > .CodeMirror-line > span span').should('have.text', '> []')
}) })
}) })
describe('for new tables', () => { describe('for new tables', () => {
beforeEach(() => { beforeEach(() => {
cy.getById('table-size-picker-popover').should('not.exist') cy.getByCypressId('table-size-picker-popover').should('not.exist')
cy.getById('table-size-picker-button').last().click() cy.getByCypressId('table-size-picker-button').last().click()
cy.getById('table-size-picker-popover').should('be.visible') cy.getByCypressId('table-size-picker-popover').should('be.visible')
}) })
it('should select table size', () => { it('should select table size', () => {
cy.getById('table-size-picker-popover') cy.getByCypressId('table-size-picker-popover')
.find('.table-container > .table-cell:nth-of-type(25)') .find('[data-cypress-col=5][data-cypress-row=3]')
.trigger('mouseover') .trigger('mouseover')
cy.getById('table-size-picker-popover') cy.getByCypressId('table-size-picker-popover').find('[data-cypress-selected="true"]').should('have.length', 15)
.find('.table-container > .table-cell[data-cypress-selected="true"]') cy.getByCypressId('table-size-picker-popover').find('.popover-header').contains('5x3')
.should('have.length', 15) cy.getByCypressId('table-size-picker-popover').find('[data-cypress-col=5][data-cypress-row=3]').click()
cy.getById('table-size-picker-popover').find('.popover-header').contains('5x3')
cy.getById('table-size-picker-popover').find('.table-container > .table-cell:nth-of-type(25)').click()
}) })
it('should open a custom table size in the modal', () => { it('should open a custom table size in the modal', () => {
cy.getById('custom-table-size-modal').should('not.exist') cy.getByCypressId('custom-table-size-modal').should('not.exist')
cy.getById('show-custom-table-modal').first().click() cy.getByCypressId('show-custom-table-modal').first().click()
cy.getById('custom-table-size-modal').should('be.visible') cy.getByCypressId('custom-table-size-modal').should('be.visible')
cy.getById('custom-table-size-modal').find('input').first().type('5') cy.getByCypressId('custom-table-size-modal').find('input').first().type('5')
cy.getById('custom-table-size-modal').find('input').last().type('3') cy.getByCypressId('custom-table-size-modal').find('input').last().type('3')
cy.getById('custom-table-size-modal').find('.modal-footer > button').click() cy.getByCypressId('custom-table-size-modal').find('.modal-footer > button').click()
}) })
afterEach(() => { afterEach(() => {
@ -227,7 +225,7 @@ describe('Toolbar Buttons', () => {
describe('for the emoji-picker', () => { describe('for the emoji-picker', () => {
it('should open overlay', () => { it('should open overlay', () => {
cy.get('emoji-picker').should('not.be.visible') cy.get('emoji-picker').should('not.be.visible')
cy.getById('show-emoji-picker').click() cy.getByCypressId('show-emoji-picker').click()
cy.get('emoji-picker').should('be.visible') cy.get('emoji-picker').should('be.visible')
}) })
}) })

View file

@ -12,32 +12,32 @@ describe('Test word count with', () => {
it('empty note', () => { it('empty note', () => {
cy.setCodemirrorContent('') cy.setCodemirrorContent('')
cy.wait(500) cy.wait(500)
cy.getById('sidebar-btn-document-info').click() cy.getByCypressId('sidebar-btn-document-info').click()
cy.getById('document-info-modal').should('be.visible') cy.getByCypressId('document-info-modal').should('be.visible')
cy.getById('document-info-word-count').should('have.text', '0') cy.getByCypressId('document-info-word-count').should('have.text', '0')
}) })
it('simple words', () => { it('simple words', () => {
cy.setCodemirrorContent('five words should be enough') cy.setCodemirrorContent('five words should be enough')
cy.wait(500) cy.wait(500)
cy.getById('sidebar-btn-document-info').click() cy.getByCypressId('sidebar-btn-document-info').click()
cy.getById('document-info-modal').should('be.visible') cy.getByCypressId('document-info-modal').should('be.visible')
cy.getById('document-info-word-count').should('have.text', '5') cy.getByCypressId('document-info-word-count').should('have.text', '5')
}) })
it('excluded codeblocks', () => { it('excluded codeblocks', () => {
cy.setCodemirrorContent('```\nthis is should be ignored\n```\n\ntwo `words`') cy.setCodemirrorContent('```\nthis is should be ignored\n```\n\ntwo `words`')
cy.wait(500) cy.wait(500)
cy.getById('sidebar-btn-document-info').click() cy.getByCypressId('sidebar-btn-document-info').click()
cy.getById('document-info-modal').should('be.visible') cy.getByCypressId('document-info-modal').should('be.visible')
cy.getById('document-info-word-count').should('have.text', '2') cy.getByCypressId('document-info-word-count').should('have.text', '2')
}) })
it('excluded images', () => { it('excluded images', () => {
cy.setCodemirrorContent('![ignored alt text](https://dummyimage.com/48) not ignored text') cy.setCodemirrorContent('![ignored alt text](https://dummyimage.com/48) not ignored text')
cy.wait(500) cy.wait(500)
cy.getById('sidebar-btn-document-info').click() cy.getByCypressId('sidebar-btn-document-info').click()
cy.getById('document-info-modal').should('be.visible') cy.getByCypressId('document-info-modal').should('be.visible')
cy.getById('document-info-word-count').should('have.text', '3') cy.getByCypressId('document-info-word-count').should('have.text', '3')
}) })
}) })

View file

@ -11,16 +11,16 @@ describe('YAML Array for deprecated syntax of document tags in frontmatter', ()
it('is shown when using old syntax', () => { it('is shown when using old syntax', () => {
cy.setCodemirrorContent('---\ntags: a, b, c\n---') cy.setCodemirrorContent('---\ntags: a, b, c\n---')
cy.getIframeBody().findById('yamlArrayDeprecationAlert').should('be.visible') cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('be.visible')
}) })
it("isn't shown when using inline yaml-array", () => { it("isn't shown when using inline yaml-array", () => {
cy.setCodemirrorContent("---\ntags: ['a', 'b', 'c']\n---") cy.setCodemirrorContent("---\ntags: ['a', 'b', 'c']\n---")
cy.getIframeBody().findById('yamlArrayDeprecationAlert').should('not.exist') cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('not.exist')
}) })
it("isn't shown when using multi line yaml-array", () => { it("isn't shown when using multi line yaml-array", () => {
cy.setCodemirrorContent('---\ntags:\n - a\n - b\n - c\n---') cy.setCodemirrorContent('---\ntags:\n - a\n - b\n - c\n---')
cy.getIframeBody().findById('yamlArrayDeprecationAlert').should('not.exist') cy.getIframeBody().findByCypressId('yamlArrayDeprecationAlert').should('not.exist')
}) })
}) })

View file

@ -5,19 +5,20 @@
*/ */
declare namespace Cypress { declare namespace Cypress {
interface Chainable { interface Chainable {
getById(id: string): Chainable<Element> getByCypressId(id: string): Chainable<Element>
findById(id: string): Chainable<Element>
findByCypressId(id: string): Chainable<Element>
} }
} }
const CYPRESS_ATTR = 'data-cypress-id' const CYPRESS_ATTR = 'data-cypress-id'
Cypress.Commands.add('getById', (id: string) => { Cypress.Commands.add('getByCypressId', (id: string) => {
return cy.get(`[${CYPRESS_ATTR}="${id}"]`) return cy.get(`[${CYPRESS_ATTR}="${id}"]`)
}) })
Cypress.Commands.add( Cypress.Commands.add(
'findById', 'findByCypressId',
{ {
prevSubject: 'element' prevSubject: 'element'
}, },

View file

@ -33,9 +33,9 @@ Cypress.Commands.add('getReveal', () => {
}) })
Cypress.Commands.add('getMarkdownBody', () => { Cypress.Commands.add('getMarkdownBody', () => {
return cy.getIframeBody(RendererType.DOCUMENT).find('.markdown-body') return cy.getIframeBody(RendererType.DOCUMENT).findByCypressId('markdown-body')
}) })
Cypress.Commands.add('getIntroBody', () => { Cypress.Commands.add('getIntroBody', () => {
return cy.getIframeBody(RendererType.INTRO).find('.markdown-body') return cy.getIframeBody(RendererType.INTRO).findByCypressId('markdown-body')
}) })

View file

@ -15,6 +15,6 @@ declare namespace Cypress {
} }
Cypress.Commands.add('logout', () => { Cypress.Commands.add('logout', () => {
cy.getById('user-dropdown').click() cy.getByCypressId('user-dropdown').click()
cy.getById('user-dropdown-sign-out-button').click() cy.getByCypressId('user-dropdown-sign-out-button').click()
}) })

View file

@ -1,28 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: CC0-1.0
*/
const path = require('path')
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@import "../../../node_modules/bootstrap/scss/functions"; @import "~bootstrap/scss/functions";
@import "../../../node_modules/bootstrap/scss/mixins"; @import "~bootstrap/scss/mixins";
@import "reboot"; @import "reboot";
@import "type"; @import "type";

View file

@ -1,7 +1,7 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: Original: Nicolas Gallagher and Jonathan Neal, Modified by the HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: MIT
*/ */
// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix // stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix

View file

@ -1,4 +1,4 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only

View file

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@import '~highlight.js/styles/github';
body.dark {
@import '~highlight.js/styles/github-dark';
}

View file

@ -1,4 +1,4 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
@ -7,10 +7,17 @@
@import "variables"; @import "variables";
@import "variables.light"; @import "variables.light";
@import "bootstrap-vendor/bootstrap"; @import "bootstrap-vendor/bootstrap";
@import '../../node_modules/react-bootstrap-typeahead/css/Typeahead'; @import '~react-bootstrap-typeahead/css/Typeahead';
@import "../../node_modules/@fontsource/source-sans-pro/index"; @import "~@fontsource/source-sans-pro/index.css";
@import "../../node_modules/twemoji-colr-font/twemoji"; @import "~twemoji-colr-font/twemoji";
@import '../../node_modules/fork-awesome/css/fork-awesome.min'; @import '~fork-awesome/css/fork-awesome.min.css';
@import '~firacode/distr/fira_code';
@import "typeahead";
@import "./button-inside";
@import "./highlight-js";
@import "./github-markdown";
@import "./markdown-tweaks";
@import "./reveal";
.text-black, body.dark .text-black { .text-black, body.dark .text-black {
color: $black; color: $black;
@ -24,7 +31,7 @@ body {
background-color: $dark; background-color: $dark;
} }
#root { #__next {
height: 100vh; height: 100vh;
} }

View file

@ -1,11 +1,9 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@import './github-markdown';
.markdown-body { .markdown-body {
position: relative; position: relative;
font-family: 'Source Sans Pro', "Twemoji", sans-serif; font-family: 'Source Sans Pro', "Twemoji", sans-serif;
@ -22,8 +20,10 @@
} }
} }
.alert > p, .alert > ul { .alert {
margin-bottom: 0; & > p, & > ul {
margin-bottom: 0;
}
} }
// This is necessary since we need to set this for all DOM Element that could be children of .markdown-body and since we support all of HTML that would literally be everything // This is necessary since we need to set this for all DOM Element that could be children of .markdown-body and since we support all of HTML that would literally be everything
@ -33,7 +33,7 @@
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
a.heading-anchor { .heading-anchor {
font-size: 0.75em; font-size: 0.75em;
margin-top: 0.25em; margin-top: 0.25em;
opacity: 0.3; opacity: 0.3;
@ -64,5 +64,4 @@
word-break: break-word; word-break: break-word;
} }
} }
} }

View file

@ -4,9 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@import '~reveal.js/dist/reveal.css';
// Default mixins and settings ----------------- // Default mixins and settings -----------------
@import "../../../node_modules/reveal.js/css/theme/template/mixins"; @import "~reveal.js/css/theme/template/mixins";
@import "../../../node_modules/reveal.js/css/theme/template/settings"; @import "~reveal.js/css/theme/template/settings";
// --------------------------------------------- // ---------------------------------------------
@ -37,5 +38,5 @@ $heading4Size: 1.0em;
// Theme template ------------------------------ // Theme template ------------------------------
@import "../../../node_modules/reveal.js/css/theme/template/theme"; @import "~reveal.js/css/theme/template/theme";
// --------------------------------------------- // ---------------------------------------------

View file

@ -125,6 +125,6 @@ $close-text-shadow: none;
// Code // Code
$pre-color: $dark; $pre-color: $dark;
@import "../../node_modules/bootstrap/scss/functions"; @import "~bootstrap/scss/functions";
@import "../../node_modules/bootstrap/scss/mixins"; @import "~bootstrap/scss/mixins";
@import "../../node_modules/bootstrap/scss/variables"; @import "~bootstrap/scss/variables";

View file

@ -1,4 +1,4 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
@ -8,9 +8,9 @@ $blue: #337ab7 !default;
$cyan: #5EB7E0 !default; $cyan: #5EB7E0 !default;
$dark: #222222 !default; $dark: #222222 !default;
@import "../../node_modules/bootstrap/scss/functions"; @import "~bootstrap/scss/functions";
@import "../../node_modules/bootstrap/scss/mixins"; @import "~bootstrap/scss/mixins";
@import "../../node_modules/bootstrap/scss/variables"; @import "~bootstrap/scss/variables";
$toast-background-color: $white; $toast-background-color: $white;

View file

@ -1,4 +1,4 @@
/*! /*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only

24
jest.config.ts Normal file
View file

@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import nextJest from 'next/jest'
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
})
// Add any custom config to be passed to Jest
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
'^@/components/(.*)$': '<rootDir>/components/$1',
},
testPathIgnorePatterns: ["/node_modules/", "/cypress/"]
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)

11
jest.setup.ts Normal file
View file

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
// Optional: configure or set up a testing framework before each test.
// If you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`
// Used for __tests__/testing-library.js
// Learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'

5
next-env.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View file

@ -1,3 +1,3 @@
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: LicenseRef-HedgeDoc-Icon-Usage-Guidelines SPDX-License-Identifier: CC0-1.0

86
next.config.js Normal file
View file

@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
console.log('Node env is', process.env.NODE_ENV)
if (process.env.NEXT_PUBLIC_USE_MOCK_API === 'true') {
console.log('Uses mock API')
} else if (!!process.env.NEXT_PUBLIC_BACKEND_BASE_URL) {
console.log('Backend base url is', process.env.NEXT_PUBLIC_BACKEND_BASE_URL)
} else {
console.error(`==============
Neither NEXT_PUBLIC_USE_MOCK_API or NEXT_PUBLIC_BACKEND_BASE_URL is set.
If you want to create a production build we suggest that you set a backend url with NEXT_PUBLIC_BACKEND_BASE_URL.
If you want to create a build that uses the mock api then use build:mock instead or set NEXT_PUBLIC_USE_MOCK_API to "true".
==============`)
process.exit(1)
}
if (!!process.env.NEXT_PUBLIC_TEST_MODE) {
console.log('Built in test mode')
}
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true'
})
/** @type {import('next').NextConfig} */
const rawNextConfig = {
webpack: (config) => {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [
{
loader: '@svgr/webpack',
options: {
svgoConfig: {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false
}
}
}
]
}
}
}
]
})
config.plugins.push(
new CopyWebpackPlugin({
patterns: [
{ from: path.join(__dirname, 'node_modules/@hpcc-js/wasm/dist/graphvizlib.wasm'), to: 'static/js' },
{ from: path.join(__dirname, 'node_modules/@hpcc-js/wasm/dist/expatlib.wasm'), to: 'static/js' },
{
from: path.join(__dirname, 'node_modules/emoji-picker-element-data/en/emojibase/data.json'),
to: 'static/js/emoji-data.json'
}
]
})
)
return config
},
reactStrictMode: true,
redirects: () => {
return Promise.resolve([
{
source: '/',
destination: '/intro',
permanent: true
}
])
}
}
const completeNextConfig = withBundleAnalyzer(rawNextConfig)
module.exports = completeNextConfig

View file

@ -1,69 +1,26 @@
{ {
"name": "react_client", "name": "@hedgedoc/react-client",
"version": "0.0.1",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"version": "0.1.0",
"scripts": { "scripts": {
"start": "cross-env PORT=3001 craco start", "build": "next build",
"start:test": "cross-env REACT_APP_TEST_MODE=true yarn start", "build:mock": "cross-env NEXT_PUBLIC_USE_MOCK_API=true next build",
"start:for-real-backend": "cross-env REACT_APP_BACKEND_BASE_URL=http://localhost:3000/ yarn start", "build:test": "cross-env NEXT_PUBLIC_USE_MOCK_API=true NEXT_PUBLIC_TEST_MODE=true next build",
"serve:build": "http-server build/ -s -p 3001 -P \"http://localhost:3001?\"", "analyze": "cross-env ANALYZE=true next build",
"build:test": "cross-env REACT_APP_TEST_MODE=true craco build", "dev": "cross-env PORT=3001 next dev",
"build:mock": "cross-env craco build", "dev:test": "cross-env PORT=3001 NEXT_PUBLIC_TEST_MODE=true next dev",
"build:production": "(cross-env node check-build-env-vars.js) && (cross-env craco build)", "dev:for-real-backend": "cross-env PORT=3001 NEXT_PUBLIC_USE_MOCK_API=false NEXT_PUBLIC_BACKEND_BASE_URL=http://localhost:3000/ next dev",
"analyze": "cross-env ANALYZE=true yarn build:mock",
"test": "craco test",
"lint": "eslint --max-warnings=0 --ext .ts,.tsx src",
"lint:fix": "eslint --fix --ext .ts,.tsx src",
"format": "prettier -c \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"", "format": "prettier -c \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"",
"format:fix": "prettier -w \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"", "format:fix": "prettier -w \"src/**/*.{ts,tsx,js}\" \"cypress/**/*.{ts,tsx}\"",
"eject": "react-scripts eject", "lint": "eslint --max-warnings=0 --ext .ts,.tsx src",
"lint:fix": "eslint --fix --ext .ts,.tsx src",
"start": "cross-env PORT=3001 next start",
"start:ci": "cross-env NEXT_PUBLIC_USE_MOCK_API=true NEXT_PUBLIC_TEST_MODE=true PORT=3001 next start",
"cy:open": "cypress open", "cy:open": "cypress open",
"cy:run:chrome": "cypress run --browser chrome", "cy:run:chrome": "cypress run --browser chrome",
"cy:run:firefox": "cypress run --browser firefox" "cy:run:firefox": "cypress run --browser firefox",
}, "test": "jest --watch",
"eslintConfig": { "test:ci": "jest --ci"
"parserOptions": {
"tsconfigRootDir": "",
"project": [
"./tsconfig.json"
]
},
"rules": {
"no-use-before-define": "off",
"no-debugger": "warn",
"default-param-last": "off",
"@typescript-eslint/consistent-type-imports": [
"error",
{
"prefer": "type-imports",
"disallowTypeAnnotations": false
}
]
},
"plugins": [
"@typescript-eslint"
],
"extends": [
"react-app",
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier"
]
},
"prettier": {
"parser": "typescript",
"singleQuote": true,
"jsxSingleQuote": true,
"semi": false,
"tabWidth": 2,
"trailingComma": "none",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always"
}, },
"browserslist": { "browserslist": {
"production": [ "production": [
@ -77,71 +34,30 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"dependencies": {}, "dependencies": {
"devDependencies": {
"@craco/craco": "6.4.3",
"@cypress/webpack-preprocessor": "5.11.0",
"@fontsource/source-sans-pro": "4.5.1", "@fontsource/source-sans-pro": "4.5.1",
"@hedgedoc/html-to-react": "1.1.1", "@hedgedoc/html-to-react": "1.1.1",
"@hedgedoc/markdown-it-image-size": "1.0.3", "@hedgedoc/markdown-it-image-size": "1.0.3",
"@hedgedoc/markdown-it-task-lists": "1.0.3", "@hedgedoc/markdown-it-task-lists": "1.0.3",
"@matejmazur/react-katex": "3.1.3", "@matejmazur/react-katex": "3.1.3",
"@redux-devtools/core": "3.9.1", "@redux-devtools/core": "3.9.1",
"@testing-library/cypress": "8.0.2", "@svgr/webpack": "6.1.2",
"@testing-library/jest-dom": "5.16.1",
"@testing-library/react": "12.1.2",
"@testing-library/user-event": "13.5.0",
"@types/codemirror": "5.60.5",
"@types/d3-graphviz": "2.6.7",
"@types/diff": "5.0.2",
"@types/dompurify": "2.3.2",
"@types/jest": "27.0.3",
"@types/js-yaml": "4.0.5",
"@types/luxon": "2.0.8",
"@types/markdown-it": "12.2.3",
"@types/markdown-it-container": "2.0.4",
"@types/markdown-it-plantuml": "1.4.1",
"@types/mermaid": "8.2.7",
"@types/node": "16.11.17",
"@types/react": "17.0.38",
"@types/react-bootstrap-typeahead": "5.1.8",
"@types/react-dom": "17.0.11",
"@types/react-router": "5.1.17",
"@types/react-router-bootstrap": "0.24.5",
"@types/react-router-dom": "5.3.2",
"@types/redux-devtools": "3.0.47",
"@types/sass": "1.43.1",
"@types/uuid": "8.3.3",
"@typescript-eslint/eslint-plugin": "5.8.0",
"@typescript-eslint/parser": "5.8.0",
"abcjs": "6.0.0-beta.35", "abcjs": "6.0.0-beta.35",
"bootstrap": "4.6.1", "bootstrap": "4.6.1",
"codemirror": "5.65.0", "codemirror": "5.65.0",
"copy-webpack-plugin": "6.4.1", "copy-webpack-plugin": "10.2.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "9.2.0",
"cypress-commands": "2.0.1",
"cypress-file-upload": "6.0.0-beta.0",
"d3-graphviz": "3.2.0", "d3-graphviz": "3.2.0",
"diff": "5.0.0", "diff": "5.0.0",
"dompurify": "2.3.4", "dompurify": "2.3.4",
"emoji-picker-element": "1.10.0", "emoji-picker-element": "1.10.0",
"emoji-picker-element-data": "1.3.0", "emoji-picker-element-data": "1.3.0",
"eslint-config-prettier": "8.3.0",
"eslint-config-react-app": "6.0.0",
"eslint-plugin-chai-friendly": "0.7.2",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-import": "2.25.3",
"eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0",
"fast-deep-equal": "3.1.3", "fast-deep-equal": "3.1.3",
"firacode": "6.2.0", "firacode": "6.2.0",
"flowchart.js": "1.17.0", "flowchart.js": "1.17.0",
"fork-awesome": "1.2.0", "fork-awesome": "1.2.0",
"highlight.js": "11.3.1", "highlight.js": "11.3.1",
"http-server": "14.0.0", "i18next": "21.6.4",
"i18next": "21.6.3",
"i18next-browser-languagedetector": "6.1.2", "i18next-browser-languagedetector": "6.1.2",
"i18next-resources-to-backend": "1.0.0", "i18next-resources-to-backend": "1.0.0",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
@ -166,38 +82,75 @@
"markmap-common": "0.1.6", "markmap-common": "0.1.6",
"markmap-lib": "0.12.0", "markmap-lib": "0.12.0",
"markmap-view": "0.2.7", "markmap-view": "0.2.7",
"mermaid": "8.13.7", "mermaid": "8.13.8",
"next": "12.0.7",
"optional-js": "2.3.0", "optional-js": "2.3.0",
"prettier": "2.5.1",
"react": "17.0.2", "react": "17.0.2",
"react-bootstrap": "1.6.4", "react-bootstrap": "1.6.4",
"react-bootstrap-typeahead": "5.2.1", "react-bootstrap-typeahead": "5.2.1",
"react-codemirror2": "7.2.1", "react-codemirror2": "7.2.1",
"react-diff-viewer": "3.1.1", "react-diff-viewer": "3.1.1",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"react-i18next": "11.15.1", "react-i18next": "11.15.2",
"react-redux": "7.2.6", "react-redux": "7.2.6",
"react-router": "5.2.1",
"react-router-bootstrap": "0.25.0",
"react-router-dom": "5.3.0",
"react-router-use-location-state": "2.5.0",
"react-scripts": "4.0.3",
"react-use": "17.3.1", "react-use": "17.3.1",
"redux": "4.1.2", "redux": "4.1.2",
"redux-devtools-extension": "2.13.9",
"reveal.js": "4.2.1", "reveal.js": "4.2.1",
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"sass": "1.45.1", "sass": "1.45.1",
"ts-loader": "9.2.6", "sharp": "0.29.3",
"ts-mockery": "1.2.0",
"twemoji-colr-font": "0.0.4", "twemoji-colr-font": "0.0.4",
"typescript": "4.5.4",
"use-resize-observer": "8.0.0", "use-resize-observer": "8.0.0",
"uuid": "8.3.2", "uuid": "8.3.2",
"vega": "5.21.0", "vega": "5.21.0",
"vega-embed": "6.20.5", "vega-embed": "6.20.5",
"vega-lite": "5.2.0", "vega-lite": "5.2.0",
"webpack-bundle-analyzer": "4.5.0",
"words-count": "2.0.2" "words-count": "2.0.2"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.7",
"@testing-library/cypress": "8.0.2",
"@testing-library/jest-dom": "5.16.1",
"@testing-library/react": "12.1.2",
"@testing-library/user-event": "13.5.0",
"@types/codemirror": "5.60.5",
"@types/d3-graphviz": "2.6.7",
"@types/diff": "5.0.2",
"@types/dompurify": "2.3.2",
"@types/js-yaml": "4.0.5",
"@types/luxon": "2.0.8",
"@types/markdown-it": "12.2.3",
"@types/markdown-it-container": "2.0.4",
"@types/markdown-it-plantuml": "1.4.1",
"@types/mermaid": "8.2.7",
"@types/node": "16.11.17",
"@types/react": "17.0.38",
"@types/react-bootstrap-typeahead": "5.1.8",
"@types/react-dom": "17.0.11",
"@types/sass": "1.43.1",
"@types/uuid": "8.3.3",
"@typescript-eslint/eslint-plugin": "5.8.1",
"@typescript-eslint/parser": "5.8.1",
"cypress": "9.2.0",
"cypress-commands": "2.0.1",
"cypress-file-upload": "6.0.0-beta.0",
"eslint": "8.5.0",
"eslint-config-next": "12.0.7",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-chai-friendly": "0.7.2",
"eslint-plugin-cypress": "2.12.1",
"eslint-plugin-import": "2.25.3",
"eslint-plugin-jsx-a11y": "6.5.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "5.2.0",
"eslint-plugin-testing-library": "5.0.1",
"jest": "27.4.5",
"prettier": "2.5.1",
"react-test-renderer": "17.0.2",
"redux-devtools-extension": "2.13.9",
"ts-loader": "9.2.6",
"ts-mockery": "1.2.0",
"ts-node": "10.4.0",
"typescript": "4.5.4"
} }
} }

View file

@ -1,3 +1,3 @@
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
SPDX-License-Identifier: AGPL-3.0-only SPDX-License-Identifier: CC0-1.0

View file

@ -0,0 +1,94 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@keyframes animation-roll {
0% {
transform: translateX(calc(-100vw / 2 - 100%)) rotateZ(0deg);
}
100% {
transform: translateX(calc(100vw / 2 + 100%)) rotateZ(720deg);
}
}
@keyframes animation-jump {
0% {
transform: scale(1, 1) translateY(0);
}
10% {
transform: scale(1.1, .9) translateY(0);
}
30% {
transform: scale(.9, 1.1) translateY(-100px);
}
50% {
transform: scale(1.05, .95) translateY(0);
}
57% {
transform: scale(1, 1) translateY(-7px);
}
64% {
transform: scale(1, 1) translateY(0);
}
100% {
transform: scale(1, 1) translateY(0);
}
}
@keyframes animation-shake {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
.animation-roll {
transform-origin: center center;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: animation-roll;
animation-timing-function: linear;
}
.animation-jump {
transform-origin: bottom;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-name: animation-jump;
animation-timing-function: cubic-bezier(0.280, 0.840, 0.420, 1);
}
.animation-shake {
animation: animation-shake 0.3s ease-in-out;
}

View file

@ -3,13 +3,8 @@
* *
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
export class ApplicationLoaderError extends Error {
.header-nav { constructor(taskName: string) {
.nav-link { super(`Task ${taskName} failed`)
border-bottom: 2px solid transparent
}
.nav-link.active {
border-bottom-color: #fff;
} }
} }

View file

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
.loader {
@import "./animations.scss";
height: 100%;
width: 100%;
&.middle, .middle {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
}

View file

@ -1,110 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
.loader {
@keyframes animation-roll {
0% {
transform: translateX(calc(-100vw / 2 - 100%)) rotateZ(0deg);
}
100% {
transform: translateX(calc(100vw / 2 + 100%)) rotateZ(720deg);
}
}
@keyframes animation-jump {
0% {
transform: scale(1, 1) translateY(0);
}
10% {
transform: scale(1.1, .9) translateY(0);
}
30% {
transform: scale(.9, 1.1) translateY(-100px);
}
50% {
transform: scale(1.05, .95) translateY(0);
}
57% {
transform: scale(1, 1) translateY(-7px);
}
64% {
transform: scale(1, 1) translateY(0);
}
100% {
transform: scale(1, 1) translateY(0);
}
}
@keyframes animation-shake {
0% {
transform: translate(1px, 1px) rotate(0deg);
}
10% {
transform: translate(-1px, -2px) rotate(-1deg);
}
20% {
transform: translate(-3px, 0px) rotate(1deg);
}
30% {
transform: translate(3px, 2px) rotate(0deg);
}
40% {
transform: translate(1px, -1px) rotate(1deg);
}
50% {
transform: translate(-1px, 2px) rotate(-1deg);
}
60% {
transform: translate(-3px, 1px) rotate(0deg);
}
70% {
transform: translate(3px, 1px) rotate(-1deg);
}
80% {
transform: translate(-1px, -1px) rotate(1deg);
}
90% {
transform: translate(1px, 2px) rotate(0deg);
}
100% {
transform: translate(1px, -2px) rotate(-1deg);
}
}
.animation-roll {
transform-origin: center center;
animation-duration: 4s;
animation-iteration-count: infinite;
animation-name: animation-roll;
animation-timing-function: linear;
}
.animation-jump {
transform-origin: bottom;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-name: animation-jump;
animation-timing-function: cubic-bezier(0.280, 0.840, 0.420, 1);
}
.animation-shake {
animation: animation-shake 0.3s ease-in-out;
}
height: 100vh;
width: 100vw;
&.middle, .middle {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.progress {
width: 50%;
}
}

Some files were not shown because too many files have changed in this diff Show more