...
 
Commits (2)
{
"presets": ["es2015", "react", "stage-2"]
}
\ No newline at end of file
......@@ -90,3 +90,6 @@ coverage/
yarn-error.log
package-lock.json
config/local*.*
test/screenshots/
test/videos/
......@@ -5,10 +5,15 @@ before_script:
test:
script:
- xvfb-run --server-args "-screen 0 1024x768x24" npm test
coverage: '/^All files\s+\|\s+(\d+.\d+)\s\|.*$/'
- npm test
artifacts:
paths:
- test/videos/
- test/screenshots/
when: always
expire_in: 1 week
variables:
DEBUG: nightmare:*
NODE_ENV: test
lint:
script:
......
......@@ -3,13 +3,7 @@ const path = require('path')
module.exports = {
'pubsweet-server': {
dbPath: path.join(__dirname, '..', 'api', 'db', 'test'),
adapter: 'memory',
secret: 'test'
},
// prevent logging from swaming test output
logger: {
debug: () => false,
info: () => false,
warn: () => false,
error: () => false
}
}
{
"fixturesFolder": "test/fixtures",
"integrationFolder": "test/specs",
"screenshotsFolder": "test/screenshots",
"videosFolder": "test/videos",
"supportFile": false
}
......@@ -11,7 +11,6 @@
"dependencies": {
"@pubsweet/logger": "^0.0.1",
"authsome": "0.0.9",
"jest": "^21.1.0",
"pubsweet": "1.0.0-alpha.6",
"pubsweet-client": "1.0.0-beta.6",
"pubsweet-component-blog": "^0.3.1",
......@@ -32,6 +31,7 @@
"devDependencies": {
"app-module-path": "^2.2.0",
"autobind-decorator": "^1.3.4",
"babel-cli": "^6.26.0",
"babel-core": "^6.14.0",
"babel-eslint": "^8.0.0",
"babel-loader": "^7.0.0",
......@@ -47,6 +47,7 @@
"compression-webpack-plugin": "^0.3.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.1",
"cypress": "^1.0.3",
"eslint": "^4.7.1",
"eslint-config-standard": "^10.2.1",
"eslint-config-standard-react": "^5.0.0",
......@@ -55,12 +56,11 @@
"eslint-plugin-react": "^7.4.0",
"eslint-plugin-standard": "^3.0.1",
"extract-text-webpack-plugin": "^2.0.0-beta.4",
"faker": "^4.1.0",
"file-loader": "^0.11.1",
"html-webpack-plugin": "^2.24.0",
"joi-browser": "^10.0.6",
"json-loader": "^0.5.4",
"nightmare": "segmentio/nightmare",
"nightmare-wait-for-url": "^0.0.2",
"node-sass": "^4.5.2",
"pouchdb-adapter-memory": "^6.1.1",
"react-hot-loader": "^3.0.0-beta.6",
......@@ -79,19 +79,8 @@
"lint": "eslint --ext js,jsx app test webpack",
"start": "pubsweet start",
"setupdb": "pubsweet setupdb",
"test": "jest"
},
"jest": {
"testMatch": [
"**/test/*.js"
],
"modulePaths": [
"<rootDir>/node_modules"
],
"testEnvironment": "node",
"unmockedModulePathPatterns": [
"/src/models"
]
"test:server": "NODE_ENV=test babel-node test/scripts/start-server.js",
"test": "NODE_ENV=test babel-node test/scripts/run-tests.js"
},
"repository": "https://gitlab.coko.foundation/pubsweet/pubsweet-starter",
"license": "MIT"
......
......@@ -2,8 +2,9 @@
"env": {
"node": true,
"es6": true,
"browser": true,
"jest": true,
"jasmine": true
"mocha": true
},
"globals": {
"cy": true
}
}
module.exports = {
dbconfig: {
username: 'fakeymcfake',
email: 'fakey_mcfake@pseudonymous.com',
password: 'correct battery horse staple',
collection: 'super secret scintillatingly scandalous documents'
},
regularuser: {
username: 'fakeymcnormal',
email: 'fakey_mcfakerer@pseudonymous.com',
password: 'incorrect solar zebra paperclip',
admin: false
},
adminuser: {
username: 'fakeymcadmin',
email: 'fakey_mcfakererer@pseudonymous.com',
password: 'pa55w0rd',
admin: true
}
}
export const admin = {
username: 'admin',
email: 'admin@example.com',
password: 'password'
}
export const collection = 'Some collection'
const Nightmare = require('nightmare')
require('nightmare-wait-for-url')
Nightmare.action('getattr', function (selector, attr, done) {
this.evaluate_now((selector, attr) => {
return document.querySelector(selector).getAttribute(attr)
}, done, selector, attr)
})
Nightmare.action('gettext', function (selector, done) {
this.evaluate_now(selector => {
return document.querySelector(selector).innerText
}, done, selector)
})
const watch = process.env.WATCH_TESTS === 'true'
module.exports = () => Nightmare({
show: watch,
openDevTools: false,
typeInterval: watch ? 200 : 10
}).viewport(1600, 1200)
const port = process.env.PORT || '3000'
const home = process.env.PUBSWEET_URL || `http://localhost:${port}`
const routeurl = route => `${home}/${route}`
const gotoroute = route => nightmare => nightmare.goto(routeurl(route))
const gohome = () => nightmare => nightmare.goto(home).wait('#root')
// signup
const signupform = {
username: 'form div:nth-child(1) input',
email: 'form div:nth-child(2) input',
password: 'form div:nth-child(3) input',
submit: 'form button'
}
const gotosignup = () => nightmare => nightmare
.use(gotoroute('signup'))
.wait('#root form button')
// login
const loginform = {
username: 'form input[type=text]',
password: 'form input[type=password]',
submit: 'form button'
}
const gotologin = () => nightmare => nightmare
.use(gotoroute('login'))
.wait('#root form button')
// teams
const newteamroot = '#root > div > div > div > div:nth-child(2) > div > div > div'
const newteamform = {
name: `${newteamroot} > div.form-group > input`,
type: `${newteamroot} > div.row > div.col-md-3 > div > div.Select-control input`,
typechoice: n => `${newteamroot} > div.row > div.col-md-3 > div > div.Select-menu-outer > div > div:nth-child(${n})`,
fragment: `${newteamroot} > div.row > div:nth-child(2) > div > div.Select-control input`,
fragmentchoice: n => `${newteamroot} > div.row > div:nth-child(2) > div > div.Select-menu-outer > div > div:nth-child(${n})`,
collection: `${newteamroot} > div.row > div:nth-child(4) > div > div.Select-control input`,
collectionchoice: n => `${newteamroot} > div.row > div:nth-child(4) > div > div.Select-menu-outer > div > div:nth-child(${n})`,
submit: `${newteamroot} > button`
}
const editteamform = {
addmember: () => {
return '#root > div > div > div > div:nth-child(2) table tbody tr:nth-child(1) > td:nth-child(5) .Select-input input'
},
memberchoice: (team, n) => {
return `#root > div > div > div > div:nth-child(2) table tbody tr:nth-child(1) > td:nth-child(5) div.Select-menu-outer > div > div:nth-child(${n})`
}
}
const gototeams = () => nightmare => nightmare.use(gotoroute('manage/teams'))
// posts
const newpostroot = '#root > div > div > div > div:nth-child(2) > div > div > div:nth-child(4)'
const newpostform = {
title: `${newpostroot} > div > input`,
submit: `${newpostroot} > button`
}
const editpostform = {
edit: 'a[title="Edit"]',
publish: 'button[title="Publish"]',
unpublish: 'button[title="Unpublish"]',
delete: 'button[title="Delete"]'
}
const gotoposts = () => nightmare => nightmare.use(gotoroute('manage/posts'))
// writer
const writerroot = '.sc-lens-writer > div > .sc-split-pane.sm-vertical'
const writer = {
title: `${writerroot} .title[contenteditable=true]`,
abstract: `${writerroot} .abstract[contenteditable=true]`,
content: `${writerroot} .document-content > div[contenteditable=true]`,
save: `${writerroot} div[title="Save"] > button`
}
// export
module.exports = {
port: port,
home: home,
routeurl: routeurl,
gotoroute: gotoroute,
gohome: gohome,
// signup
gotosignup: gotosignup,
signupform: signupform,
signup: user => nightmare => nightmare
.use(gotosignup())
.type(signupform.username, user.username)
.type(signupform.email, user.email)
.type(signupform.password, user.password)
.click(signupform.submit),
// login
gotologin: gotologin,
loginform: loginform,
login: user => nightmare => nightmare
.use(gotologin())
.type(loginform.username, user.username)
.type(loginform.password, user.password)
.click(loginform.submit),
logout: () => nightmare => nightmare
.use(gotoposts())
.wait('.logout')
.click('.logout > a'),
// teams
gotoManageTeams: gototeams,
newteamform: newteamform,
createteam: team => nightmare => nightmare
.use(gototeams())
.waitForUrl(/manage.teams/)
.wait('input')
.type(newteamform.name, team.name)
.type(newteamform.type, team.type)
.click(newteamform.typechoice(1))
.wait(200)
.type(
team.fragment ? newteamform.fragment : newteamform.collection,
team.fragment ? team.fragment : team.collection
)
.click(
team.fragment
? newteamform.fragmentchoice(1)
: newteamform.collectionchoice(1)
)
.wait(200)
.click(newteamform.submit),
addteammember: update => nightmare => nightmare
.use(gototeams())
.waitForUrl(/manage.teams/)
.wait('input')
.type(editteamform.addmember(update.team), `${update.member}`)
.click(editteamform.memberchoice(update.team, 1)),
// posts
gotoManagePosts: gotoposts,
createpost: post => nightmare => nightmare
.use(gotoposts())
.waitForUrl(/manage.posts/)
.wait('input')
.type(newpostform.title, post.title)
.click(newteamform.submit),
publishpost: () => nightmare => nightmare
.use(gotoposts())
.waitForUrl(/manage.posts/)
.wait('input')
.click(editpostform.publish),
unpublishpost: () => nightmare => nightmare
.use(gotoposts())
.waitForUrl(/manage.posts/)
.wait('input')
.click(editpostform.unpublish),
writepost: post => nightmare => nightmare
.use(gotoposts())
.waitForUrl(/manage.posts/)
.wait('input')
.click(editpostform.edit)
.waitForUrl(/sciencewriter/)
.wait('.title')
.wait(200)
.insert(writer.title, false)
.type(writer.title, post.title)
.type(writer.abstract, post.abstract)
.type(writer.content, post.content)
.click(writer.abstract).wait(200)
.click(writer.save),
readpost: () => nightmare => nightmare
.use(gohome())
.waitForUrl(home)
.wait('.blogpost')
.click('.blogpost a')
.waitForUrl(/sciencewriter/)
.wait(writerroot)
}
#!/usr/bin/env node
import { setupDb } from '@pubsweet/db-manager'
import createDb from 'pubsweet-server/src/db'
import start from 'pubsweet/src/start'
import * as fixtures from './fixtures'
let server
export async function setup () {
server = await start()
global.db = createDb()
await setupDb(Object.assign({}, fixtures.admin, {collection: fixtures.collection}))
}
export async function teardown () {
await global.db.destroy()
server.close()
}
export {default as login} from './login'
export {default as signup} from './signup'
export {default as managePosts} from './manage/posts'
const login = {
url: `http://localhost:${process.env.PORT || 3000}/login`,
username: 'form input[type=text]',
password: 'form input[type=password]',
submit: 'form button',
signUp: 'form a:first',
resetPassword: 'form a:last',
alert: '.alert',
doLogin: (username, password) => {
cy.visit(login.url)
cy.get(login.username).type(username)
cy.get(login.password).type(password)
cy.get(login.submit).click()
}
}
export default login
const managePosts = {
url: `http://localhost:${process.env.PORT || 3000}/manage/posts`,
title: 'h2',
post: n => `table tr:${typeof n === 'number' ? `nth(${n + 1})` : n}`,
postTitle: n => `${managePosts.post(n)} label`,
postEdit: n => `${managePosts.post(n)} button[title=Edit]`,
postPublish: n => `${managePosts.post(n)} button[title=Publish]`,
postUnpublish: n => `${managePosts.post(n)} button[title=Unpublish]`,
postDelete: n => `${managePosts.post(n)} button[title=Delete]`,
newPostInput: 'input[id="fragment.title"]',
newPostButton: 'button[title=Create]'
}
export default managePosts
const signup = {
url: `http://localhost:${process.env.PORT || 3000}/signup`,
title: 'h1',
username: 'form input[type=text]:first',
email: 'form input[type=text]:last',
password: 'form input[type=password]',
submit: 'form button',
login: 'form a'
}
export default signup
#!/usr/bin/env node
import cypress from 'cypress'
import { setup } from '../helpers/setup'
setup()
.then(() => cypress.run())
.then(result => process.exit(result.failures))
#!/usr/bin/env node
import { setup } from '../helpers/setup'
setup()
import faker from 'faker'
import { login, managePosts } from '../pageObjects/index'
import * as fixtures from '../helpers/fixtures'
describe('Admin user', () => {
it('Posts manager journey', () => {
login.doLogin(fixtures.admin.username, fixtures.admin.password)
// create a post
const postTitle = faker.lorem.words()
cy.get(managePosts.newPostInput).type(postTitle)
cy.get(managePosts.newPostButton).click()
cy.get(managePosts.postTitle('last')).should('contain', postTitle)
// publish it
cy.get(managePosts.postPublish('last')).click()
cy.get(managePosts.postPublish('last')).should('not.exist')
cy.get(managePosts.postUnpublish('last')).should('exist')
// delete it
cy.get(managePosts.postDelete('last')).click()
cy.get(managePosts.postTitle('last')).should('not.contain', postTitle)
})
})
import { login, signup, managePosts } from '../pageObjects'
import faker from 'faker'
describe('Guest user', () => {
it('Signup jorney', () => {
const user = {
username: faker.internet.domainWord(),
email: faker.internet.email(),
password: faker.internet.password()
}
// cannot log in
login.doLogin(user.username, user.password)
cy.get(login.alert).should('contain', 'Unauthorized')
// signup
cy.get(login.signUp).click()
cy.get(signup.title).should('contain', 'Sign up')
cy.get(signup.username).type(user.username)
cy.get(signup.email).type(user.email)
cy.get(signup.password).type(user.password)
cy.get(signup.submit).click()
// can log in
login.doLogin(user.username, user.password)
cy.url().should('eq', managePosts.url)
})
it.skip('guest can navigate to reset password page', () => {
cy.visit(login.url)
cy.get(login.resetPassword).click()
cy.get(signup.title).should('contain', 'Reset password')
})
})
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1200000
const logger = require('@pubsweet/logger')
const fixtures = require('./fixtures')
const dbConfig = fixtures.dbconfig
const flow = require('./helpers/flow')
const pubsweet = require('./helpers/pubsweet')
const dbManager = require('@pubsweet/db-manager')
const start = require('pubsweet/src/start/index.js')
describe('start', () => {
let server
beforeAll(async () => {
await dbManager.setupDb(dbConfig)
logger.info('Starting server')
server = await start()
logger.info('Server started')
})
afterAll(done => {
logger.info('Stopping the server')
server.close(() => {
logger.info('Server stopped')
done()
})
})
// FLOW:
// - start the app
// - visit the login page
// - login as the admin user
// - visit the homepage
it('should allow admin to log in', async () => {
const headingText = await flow()
.use(pubsweet.login(dbConfig))
.waitForUrl(/manage\/posts/)
.wait('h2')
.evaluate(() => document.querySelector('h2').innerText)
.end()
expect(headingText).toBe(dbConfig.collection)
})
})
const path = require('path')
module.exports = [
new RegExp('authsome'),
new RegExp(path.join(__dirname, '..', 'node_modules', 'pubsweet-client', 'src')),
new RegExp(path.join(__dirname, '..', 'app')),
new RegExp(path.join(__dirname, '..', 'node_modules', 'pubsweet-[^/\\\\]*(?!.*/node_modules)'))
......
This diff is collapsed.