mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-27 13:34:28 -04:00
added e2e tests (#298)
- added e2e tests for - banner - history - intro - language - link - added e2e workflow - added cypress badge to README
This commit is contained in:
parent
1a5d4f6db8
commit
f0fe7f5ac2
26 changed files with 1332 additions and 77 deletions
23
cypress/.eslintrc.json
Normal file
23
cypress/.eslintrc.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"parserOptions": {
|
||||
"tsconfigRootDir": "",
|
||||
"project": [
|
||||
"./cypress/tsconfig.json"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
"cypress",
|
||||
"chai-friendly"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:cypress/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-expressions": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"chai-friendly/no-unused-expressions": 2
|
||||
},
|
||||
"env": {
|
||||
"cypress/globals": true
|
||||
}
|
||||
}
|
30
cypress/fixtures/languages.ts
Normal file
30
cypress/fixtures/languages.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
export const languages: string[] = [
|
||||
'English',
|
||||
'简体中文',
|
||||
'繁體中文',
|
||||
'Français',
|
||||
'Deutsch',
|
||||
'日本語',
|
||||
'Español',
|
||||
'Català',
|
||||
'Ελληνικά',
|
||||
'Português',
|
||||
'Italiano',
|
||||
'Türkçe',
|
||||
'Русский',
|
||||
'Nederlands',
|
||||
'Hrvatski',
|
||||
'Polski',
|
||||
'Українська',
|
||||
'हिन्दी',
|
||||
'Svenska',
|
||||
'Esperanto',
|
||||
'Dansk',
|
||||
'한국어',
|
||||
'Bahasa Indonesia',
|
||||
'Cрпски',
|
||||
'Tiếng Việt',
|
||||
'العربية',
|
||||
'Česky',
|
||||
'Slovensky'
|
||||
]
|
26
cypress/integration/banner.spec.ts
Normal file
26
cypress/integration/banner.spec.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { banner } from '../support/config'
|
||||
|
||||
describe('Banner', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/')
|
||||
expect(localStorage.getItem('bannerTimeStamp')).to.be.null
|
||||
})
|
||||
|
||||
it('shows the correct alert banner text', () => {
|
||||
cy.get('.alert-primary.show')
|
||||
.contains(banner.text)
|
||||
})
|
||||
|
||||
it('can be dismissed', () => {
|
||||
cy.get('.alert-primary.show')
|
||||
.contains(banner.text)
|
||||
cy.get('.alert-primary.show')
|
||||
.find('.fa-times')
|
||||
.click()
|
||||
.then(() => {
|
||||
expect(localStorage.getItem('bannerTimeStamp')).to.equal(banner.timestamp)
|
||||
})
|
||||
cy.get('.alert-primary.show')
|
||||
.should('not.exist')
|
||||
})
|
||||
})
|
35
cypress/integration/history.spec.ts
Normal file
35
cypress/integration/history.spec.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
describe('History', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/history')
|
||||
})
|
||||
|
||||
describe('History Mode', () => {
|
||||
it('Cards', () => {
|
||||
cy.get('div.card')
|
||||
})
|
||||
|
||||
it('Table', () => {
|
||||
cy.get('i.fa-table')
|
||||
.click()
|
||||
cy.get('table.history-table')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Pinning', () => {
|
||||
it('Cards', () => {
|
||||
cy.get('.fa-thumb-tack')
|
||||
.first()
|
||||
.click()
|
||||
cy.get('.modal-dialog')
|
||||
.should('be.visible')
|
||||
})
|
||||
|
||||
it('Table', () => {
|
||||
cy.get('.fa-thumb-tack')
|
||||
.first()
|
||||
.click()
|
||||
cy.get('.modal-dialog')
|
||||
.should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
58
cypress/integration/intro.spec.ts
Normal file
58
cypress/integration/intro.spec.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
describe('Intro', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
describe('Cover Button are hidden when logged in', () => {
|
||||
it('Sign in Cover Button', () => {
|
||||
cy.get('.cover-button.btn-success')
|
||||
.should('not.exist')
|
||||
})
|
||||
|
||||
it('Features Cover Button', () => {
|
||||
cy.get('.cover-button.btn-primary')
|
||||
.should('not.exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Cover Button are shown when logged out', () => {
|
||||
beforeEach(() => {
|
||||
cy.logout()
|
||||
})
|
||||
|
||||
it('Sign in Cover Button', () => {
|
||||
cy.get('.cover-button.btn-success')
|
||||
.should('exist')
|
||||
})
|
||||
|
||||
it('Features Cover Button', () => {
|
||||
cy.get('.cover-button.btn-primary')
|
||||
.should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Version', () => {
|
||||
it('can be opened', () => {
|
||||
cy.get('#versionModal')
|
||||
.should('not.be.visible')
|
||||
cy.get('#version')
|
||||
.click()
|
||||
cy.get('#versionModal')
|
||||
.should('be.visible')
|
||||
})
|
||||
|
||||
it('can be closed', () => {
|
||||
cy.get('#versionModal')
|
||||
.should('not.be.visible')
|
||||
cy.get('#version')
|
||||
.click()
|
||||
cy.get('#versionModal')
|
||||
.should('be.visible')
|
||||
cy.get('body')
|
||||
.click()
|
||||
cy.get('#versionModal')
|
||||
.should('not.be.visible')
|
||||
})
|
||||
})
|
||||
})
|
30
cypress/integration/language.spec.ts
Normal file
30
cypress/integration/language.spec.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { languages } from '../fixtures/languages'
|
||||
|
||||
describe('Languages', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
it('all languages are available', () => {
|
||||
cy.get('option')
|
||||
.as('languages')
|
||||
cy.get('@languages')
|
||||
.should('have.length', 28)
|
||||
languages.forEach(language => {
|
||||
cy.get('@languages').contains(language)
|
||||
})
|
||||
})
|
||||
|
||||
it('language changes affect the UI', () => {
|
||||
cy.get('select')
|
||||
.select('English')
|
||||
cy.get('.d-inline-flex.btn-primary')
|
||||
.find('span')
|
||||
.contains('New note')
|
||||
cy.get('select')
|
||||
.select('Deutsch')
|
||||
cy.get('.d-inline-flex.btn-primary')
|
||||
.find('span')
|
||||
.contains('Neue Notiz')
|
||||
})
|
||||
})
|
165
cypress/integration/link.spec.ts
Normal file
165
cypress/integration/link.spec.ts
Normal file
|
@ -0,0 +1,165 @@
|
|||
import '../support/index'
|
||||
|
||||
describe('Links Intro', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/')
|
||||
})
|
||||
|
||||
describe('Cover Buttons', () => {
|
||||
beforeEach(() => {
|
||||
cy.logout()
|
||||
})
|
||||
|
||||
it('Sign in Cover Button', () => {
|
||||
cy.get('.cover-button.btn-success')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/login')
|
||||
})
|
||||
|
||||
it('Features Cover Button', () => {
|
||||
cy.get('.cover-button.btn-primary')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/features')
|
||||
})
|
||||
})
|
||||
|
||||
it('History', () => {
|
||||
cy.get('#navLinkHistory')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/history')
|
||||
cy.get('#navLinkIntro')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/intro')
|
||||
})
|
||||
|
||||
describe('Menu Buttons logged out', () => {
|
||||
beforeEach(() => {
|
||||
cy.logout()
|
||||
})
|
||||
|
||||
it('New guest note', () => {
|
||||
cy.get('.d-inline-flex.btn-primary')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/new')
|
||||
})
|
||||
|
||||
it('Sign In', () => {
|
||||
cy.get('.btn-success.btn-sm')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/login')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Menu Buttons logged in', () => {
|
||||
it('New note', () => {
|
||||
cy.get('.d-inline-flex.btn-primary').click()
|
||||
cy.url()
|
||||
.should('include', '/new')
|
||||
})
|
||||
|
||||
describe('User Menu', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('#dropdown-user').click()
|
||||
})
|
||||
|
||||
it('Features', () => {
|
||||
cy.get('a.dropdown-item > i.fa-bolt')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/features')
|
||||
})
|
||||
|
||||
it('Features', () => {
|
||||
cy.get('a.dropdown-item > i.fa-user')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/profile')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Feature Links', () => {
|
||||
it('Share-Notes', () => {
|
||||
cy.get('i.fa-bolt.fa-3x')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/features#Share-Notes')
|
||||
})
|
||||
|
||||
it('MathJax', () => {
|
||||
cy.get('i.fa-bar-chart.fa-3x')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/features#MathJax')
|
||||
})
|
||||
|
||||
it('Slide-Mode', () => {
|
||||
cy.get('i.fa-television.fa-3x')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/features#Slide-Mode')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Powered By Links', () => {
|
||||
it('CodiMD', () => {
|
||||
cy.get('a[href="https://codimd.org"]')
|
||||
.checkExternalLink('https://codimd.org')
|
||||
})
|
||||
|
||||
it('Releases', () => {
|
||||
cy.get('a[href*="/n/release-notes"]')
|
||||
.click()
|
||||
cy.url()
|
||||
.should('include', '/n/release-notes')
|
||||
})
|
||||
|
||||
it('Privacy', () => {
|
||||
cy.get('a[href="https://example.com/privacy"]')
|
||||
.checkExternalLink('https://example.com/privacy')
|
||||
})
|
||||
|
||||
it('TermsOfUse', () => {
|
||||
cy.get('a[href="https://example.com/termsOfUse"]')
|
||||
.checkExternalLink('https://example.com/termsOfUse')
|
||||
})
|
||||
|
||||
it('Imprint', () => {
|
||||
cy.get('a[href="https://example.com/imprint"]')
|
||||
.checkExternalLink('https://example.com/imprint')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Follow us Links', () => {
|
||||
it('Github', () => {
|
||||
cy.get('a[href="https://github.com/codimd/server"]')
|
||||
.checkExternalLink('https://github.com/codimd/server')
|
||||
})
|
||||
|
||||
it('Discourse', () => {
|
||||
cy.get('a[href="https://community.codimd.org"]')
|
||||
.checkExternalLink('https://community.codimd.org')
|
||||
})
|
||||
|
||||
it('Matrix', () => {
|
||||
cy.get('a[href="https://riot.im/app/#/room/#codimd:matrix.org"]')
|
||||
.checkExternalLink('https://riot.im/app/#/room/#codimd:matrix.org')
|
||||
})
|
||||
|
||||
it('Mastodon', () => {
|
||||
cy.get('a[href="https://social.codimd.org/mastodon"]')
|
||||
.checkExternalLink('https://social.codimd.org/mastodon')
|
||||
})
|
||||
|
||||
it('POEditor', () => {
|
||||
cy.get('a[href="https://translate.codimd.org"]')
|
||||
.checkExternalLink('https://translate.codimd.org')
|
||||
})
|
||||
})
|
||||
})
|
15
cypress/support/checkLinks.ts
Normal file
15
cypress/support/checkLinks.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Custom command to check an external Link.
|
||||
* @example cy.get(a#extern).checkExternalLink('http://example.com')
|
||||
*/
|
||||
checkExternalLink (url: string): Chainable<Element>
|
||||
}
|
||||
}
|
||||
|
||||
Cypress.Commands.add('checkExternalLink', { prevSubject: 'element' }, ($element: JQuery, url: string) => {
|
||||
cy.wrap($element).should('have.attr', 'href', url)
|
||||
.should('have.attr', 'target', '_blank')
|
||||
})
|
47
cypress/support/config.ts
Normal file
47
cypress/support/config.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
export const banner = {
|
||||
text: 'This is the mock banner call',
|
||||
timestamp: '2020-05-22T20:46:08.962Z'
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
cy.server()
|
||||
cy.route({
|
||||
url: '/api/v2/config',
|
||||
response: {
|
||||
allowAnonymous: true,
|
||||
authProviders: {
|
||||
facebook: true,
|
||||
github: true,
|
||||
twitter: true,
|
||||
gitlab: true,
|
||||
dropbox: true,
|
||||
ldap: true,
|
||||
google: true,
|
||||
saml: true,
|
||||
oauth2: true,
|
||||
email: true,
|
||||
openid: true
|
||||
},
|
||||
branding: {
|
||||
name: 'ACME Corp',
|
||||
logo: 'http://localhost:3000/acme.png'
|
||||
},
|
||||
banner: banner,
|
||||
customAuthNames: {
|
||||
ldap: 'FooBar',
|
||||
oauth2: 'Olaf2',
|
||||
saml: 'aufSAMLn.de'
|
||||
},
|
||||
specialLinks: {
|
||||
privacy: 'https://example.com/privacy',
|
||||
termsOfUse: 'https://example.com/termsOfUse',
|
||||
imprint: 'https://example.com/imprint'
|
||||
},
|
||||
version: {
|
||||
version: 'mock',
|
||||
sourceCodeUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||
issueTrackerUrl: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
18
cypress/support/index.ts
Normal file
18
cypress/support/index.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
// ***********************************************************
|
||||
// This example support/index.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
import './checkLinks'
|
||||
import './config'
|
||||
import './login'
|
15
cypress/support/login.ts
Normal file
15
cypress/support/login.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Custom command to log the user out.
|
||||
* @example cy.logout()
|
||||
*/
|
||||
logout (): Chainable<Window>
|
||||
}
|
||||
}
|
||||
|
||||
Cypress.Commands.add('logout', () => {
|
||||
cy.get('#dropdown-user').click()
|
||||
cy.get('.fa-sign-out').click()
|
||||
})
|
12
cypress/tsconfig.json
Normal file
12
cypress/tsconfig.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"baseUrl": "../node_modules",
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
22
cypress/webpack.config.js
Normal file
22
cypress/webpack.config.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
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')
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue