diff --git a/mpwo_client/e2e/index.test.js b/mpwo_client/e2e/index.test.js index 220832db..f61a9761 100644 --- a/mpwo_client/e2e/index.test.js +++ b/mpwo_client/e2e/index.test.js @@ -1,8 +1,9 @@ import { Selector } from 'testcafe' -const TEST_URL = process.env.TEST_URL +import { TEST_URL } from './utils' +// eslint-disable-next-line no-undef fixture('/').page(`${TEST_URL}/`) test('users should be able to view the \'/\' page', async t => { diff --git a/mpwo_client/e2e/register.test.js b/mpwo_client/e2e/register.test.js new file mode 100644 index 00000000..03652fd5 --- /dev/null +++ b/mpwo_client/e2e/register.test.js @@ -0,0 +1,185 @@ +import { Selector } from 'testcafe' + +import { TEST_URL } from './utils' + +const randomstring = require('randomstring') + +let username = randomstring.generate(8) +const email = `${username}@test.com` +const password = 'lentghOk' + + +// eslint-disable-next-line no-undef +fixture('/register').page(`${TEST_URL}/register`) + +test('should display the registration form', async t => { + await t + .navigateTo(`${TEST_URL}/register`) + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('form').exists).ok() + .expect(Selector('input[name="username"]').exists).ok() + .expect(Selector('input[name="email"]').exists).ok() + .expect(Selector('input[name="password"]').exists).ok() + .expect(Selector('input[name="passwordConf"]').exists).ok() +}) + +test('should allow a user to register', async t => { + + // register user + await t + .navigateTo(`${TEST_URL}/register`) + .expect(Selector('H1').withText('Register').exists).ok() + .typeText('input[name="username"]', username) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user is redirected to '/' + await t + .expect(Selector('H1').withText('Dashboard').exists).ok() + .expect(Selector('H1').withText('Register').exists).notOk() +}) + +test('should throw an error if the username is taken', async t => { + + // register user with duplicate user name + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', username) + .typeText('input[name="email"]', `${email}2`) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Sorry. That user already exists.').exists).ok() +}) + +username = randomstring.generate(8) + +test('should throw an error if the email is taken', async t => { + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', `${username}2`) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Sorry. That user already exists.').exists).ok() +}) + +test('should throw an error if the username is too short', async t => { + + const shortUsername = 'a' + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', `${shortUsername}`) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Username: 3 to 12 characters required.').exists).ok() +}) + +test('should throw an error if the user is too long', async t => { + + const longUsername = randomstring.generate(20) + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', `${longUsername}`) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Username: 3 to 12 characters required.').exists).ok() +}) + +test('should throw an error if the email is invalid', async t => { + + const invalidEmail = `${username}@test` + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', username) + .typeText('input[name="email"]', invalidEmail) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', password) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Valid email must be provided.').exists).ok() +}) + +test('should throw an error if passwords don\'t match', async t => { + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', username) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', password) + .typeText('input[name="passwordConf"]', `${password}2`) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Password and password confirmation don\'t match.').exists).ok() +}) + +test('should throw an error if the password is too short', async t => { + + const invalidPassword = '1234567' + + // register user with duplicate email + await t + .navigateTo(`${TEST_URL}/register`) + .typeText('input[name="username"]', username) + .typeText('input[name="email"]', email) + .typeText('input[name="password"]', invalidPassword) + .typeText('input[name="passwordConf"]', invalidPassword) + .click(Selector('input[type="submit"]')) + + // assert user registration failed + await t + .expect(Selector('H1').withText('Register').exists).ok() + .expect(Selector('H1').withText('Dashboard').exists).notOk() + .expect(Selector('code').withText( + 'Password: 8 characters required.').exists).ok() +}) diff --git a/mpwo_client/e2e/utils.js b/mpwo_client/e2e/utils.js new file mode 100644 index 00000000..a0309e81 --- /dev/null +++ b/mpwo_client/e2e/utils.js @@ -0,0 +1 @@ +export const TEST_URL = process.env.TEST_URL diff --git a/package.json b/package.json index 657825af..7364c2e9 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "eslint-plugin-import": "^2.8.0", "eslint-plugin-react": "^7.5.1", "eslint-plugin-testcafe": "^0.2.1", + "randomstring": "^1.1.5", "testcafe": "^0.18.6" } } diff --git a/yarn.lock b/yarn.lock index 89ca43da..f424870b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -283,6 +283,10 @@ array-union@^1.0.1: dependencies: array-uniq "^1.0.1" +array-uniq@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" + array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -5596,6 +5600,12 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" +randomstring@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/randomstring/-/randomstring-1.1.5.tgz#6df0628f75cbd5932930d9fe3ab4e956a18518c3" + dependencies: + array-uniq "1.0.2" + range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"