parent
cd72059536
commit
77d286ebb6
@ -0,0 +1,24 @@
|
||||
import Config
|
||||
|
||||
import_config "dev.exs"
|
||||
|
||||
config :mobilizon, MobilizonWeb.Endpoint,
|
||||
http: [
|
||||
port: 4000
|
||||
],
|
||||
url: [
|
||||
host: "localhost",
|
||||
port: 4000,
|
||||
scheme: "http"
|
||||
],
|
||||
debug_errors: true,
|
||||
code_reloader: false,
|
||||
check_origin: false,
|
||||
# Somehow this can't be merged properly with the dev config some we got this…
|
||||
watchers: [
|
||||
yarn: [cd: Path.expand("../js", __DIR__)]
|
||||
]
|
||||
|
||||
config :mobilizon, sql_sandbox: true
|
||||
|
||||
config :mobilizon, Mobilizon.Storage.Repo, pool: Ecto.Adapters.SQL.Sandbox
|
@ -1,10 +1,10 @@
|
||||
FROM elixir:latest
|
||||
LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
|
||||
|
||||
ENV REFRESHED_AT=2019-07-03
|
||||
RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg
|
||||
ENV REFRESHED_AT=2019-10-06
|
||||
RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2
|
||||
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash && apt-get install nodejs -yq
|
||||
RUN npm install -g yarn
|
||||
RUN npm install -g yarn wait-on
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
RUN mix local.hex --force && mix local.rebar --force
|
||||
RUN curl http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz --output GeoLite2-City.tar.gz -s && tar zxf GeoLite2-City.tar.gz && mkdir -p /usr/share/GeoIP && mv GeoLite2-City_*/GeoLite2-City.mmdb /usr/share/GeoIP/GeoLite2-City.mmdb
|
||||
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"pluginsFile": "tests/e2e/plugins/index.js",
|
||||
"projectId": "86dpkx",
|
||||
"baseUrl": "http://localhost:4000",
|
||||
"viewportWidth": 1920,
|
||||
"viewportHeight": 1080
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// https://docs.cypress.io/guides/guides/plugins-guide.html
|
||||
|
||||
// if you need a custom webpack configuration you can uncomment the following import
|
||||
// and then use the `file:preprocessor` event
|
||||
// as explained in the cypress docs
|
||||
// https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies, global-require, arrow-body-style */
|
||||
// const webpack = require('@cypress/webpack-preprocessor')
|
||||
|
||||
module.exports = (on, config) => {
|
||||
// on('file:preprocessor', webpack({
|
||||
// webpackOptions: require('@vue/cli-service/webpack.config'),
|
||||
// watchOptions: {}
|
||||
// }))
|
||||
|
||||
return Object.assign({}, config, {
|
||||
fixturesFolder: 'tests/e2e/fixtures',
|
||||
integrationFolder: 'tests/e2e/specs',
|
||||
screenshotsFolder: 'tests/e2e/screenshots',
|
||||
videosFolder: 'tests/e2e/videos',
|
||||
supportFile: 'tests/e2e/support/index.js'
|
||||
})
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
// Set the en-US language just in case
|
||||
export const onBeforeLoad = (window) => Object.defineProperty(window.navigator, 'language', { value: 'en-US' });
|
@ -0,0 +1,42 @@
|
||||
// https://docs.cypress.io/api/introduction/api.html
|
||||
import { onBeforeLoad } from './browser-language';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.restoreLocalStorage();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.saveLocalStorage();
|
||||
});
|
||||
|
||||
describe('Homepage', () => {
|
||||
it('Checks the footer', () => {
|
||||
cy.visit('/', { onBeforeLoad });
|
||||
cy.get('#mobilizon').find('footer').contains('The Mobilizon Contributors');
|
||||
|
||||
cy.contains('About').should('have.attr', 'href').and('eq', 'https://joinmobilizon.org');
|
||||
|
||||
cy.contains('License').should('have.attr', 'href').and('eq', 'https://framagit.org/framasoft/mobilizon/blob/master/LICENSE');
|
||||
});
|
||||
|
||||
it('Tries to register from the hero section', () => {
|
||||
cy.visit('/', { onBeforeLoad });
|
||||
|
||||
cy.get('.hero-body').contains('Sign up').click();
|
||||
cy.url().should('include', '/register/user');
|
||||
|
||||
});
|
||||
it('Tries to register from the navbar', () => {
|
||||
cy.visit('/', { onBeforeLoad });
|
||||
|
||||
cy.get('nav.navbar').contains('Sign up').click();
|
||||
cy.url().should('include', '/register/user');
|
||||
});
|
||||
|
||||
it('Tries to connect from the navbar', () => {
|
||||
cy.visit('/', { onBeforeLoad });
|
||||
|
||||
cy.get('nav.navbar').contains('Log in').click();
|
||||
cy.url().should('include', '/login');
|
||||
});
|
||||
});
|
@ -0,0 +1,45 @@
|
||||
import { onBeforeLoad } from './browser-language';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.restoreLocalStorage();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.saveLocalStorage();
|
||||
});
|
||||
|
||||
describe('Login', () => {
|
||||
it('Tests that everything is present', () => {
|
||||
cy.visit('/login', { onBeforeLoad });
|
||||
|
||||
cy.get('form .field').first().contains('label', 'Email');
|
||||
cy.get('form .field').last().contains('label', 'Password');
|
||||
cy.get('form').contains('button.button', 'Login');
|
||||
cy.get('form').contains('.control a.button', 'Forgot your password ?').click();
|
||||
cy.url().should('include', '/password-reset/send');
|
||||
cy.go('back');
|
||||
|
||||
cy.get('form').contains('.control a.button', 'Register').click();
|
||||
cy.url().should('include', '/register/user');
|
||||
|
||||
cy.go('back');
|
||||
});
|
||||
|
||||
it('Tries to login with incorrect credentials', () => {
|
||||
cy.visit('/login', { onBeforeLoad });
|
||||
cy.get('input[type=email]').type('notanemail').should('have.value', 'notanemail');
|
||||
cy.get('input[type=password]').click();
|
||||
cy.contains('button.button.is-primary.is-large', 'Login').click();
|
||||
cy.get('form .field').first().contains('p.help.is-danger', 'Please include an \'@\' in the email address.');
|
||||
cy.get('form .field').last().contains('p.help.is-danger', 'Please fill out this field.');
|
||||
});
|
||||
|
||||
it('Tries to login with invalid credentials', () => {
|
||||
cy.visit('/login', { onBeforeLoad });
|
||||
cy.get('input[type=email]').type('test@email.com').should('have.value', 'test@email.com');
|
||||
cy.get('input[type=password]').type('badPassword').should('have.value', 'badPassword');
|
||||
cy.contains('button.button.is-primary.is-large', 'Login').click();
|
||||
|
||||
cy.contains('.message.is-danger', 'User with email not found');
|
||||
});
|
||||
});
|
@ -0,0 +1,69 @@
|
||||
import { onBeforeLoad } from './browser-language';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.restoreLocalStorage();
|
||||
cy.checkoutSession();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.saveLocalStorage();
|
||||
cy.dropSession();
|
||||
});
|
||||
|
||||
describe('Registration', () => {
|
||||
it('Tests that everything is present', () => {
|
||||
cy.visit('/register/user', { onBeforeLoad });
|
||||
|
||||
cy.get('form .field').first().contains('label', 'Email');
|
||||
cy.get('form .field').eq(1).contains('label', 'Password');
|
||||
|
||||
cy.get('input[type=email]').click();
|
||||
cy.get('input[type=password]').type('short').should('have.value', 'short');
|
||||
cy.get('form').contains('button.button.is-primary', 'Register');
|
||||
cy.get('form .field').first().contains('p.help.is-danger', 'Please fill out this field.');
|
||||
|
||||
cy.get('form').contains('.control a.button', 'Didn\'t receive the instructions ?').click();
|
||||
cy.url().should('include', '/resend-instructions');
|
||||
cy.go('back');
|
||||
|
||||
cy.get('form').contains('.control a.button', 'Login').click();
|
||||
cy.url().should('include', '/login');
|
||||
|
||||
cy.go('back');
|
||||
});
|
||||
|
||||
it('Tests that registration works', () => {
|
||||
cy.visit('/register/user', { onBeforeLoad });
|
||||
cy.get('input[type=email]').type('user@email.com');
|
||||
cy.get('input[type=password]').type('userPassword');
|
||||
cy.get('form').contains('button.button.is-primary', 'Register').click();
|
||||
|
||||
cy.url().should('include', '/register/profile');
|
||||
cy.get('form .field').first().contains('label', 'Username').parent().find('input').type('tester');
|
||||
cy.get('form .field').eq(2).contains('label', 'Displayed name').parent().find('input').type('tester account');
|
||||
cy.get('form .field').eq(3).contains('label', 'Description').parent().find('textarea').type('This is a test account');
|
||||
cy.get('form .field').last().contains('button', 'Create my profile').click();
|
||||
|
||||
cy.contains('article.message.is-success', 'Your account is nearly ready, tester').contains('A validation email was sent to user@email.com');
|
||||
|
||||
cy.visit('/sent_emails');
|
||||
|
||||
cy.get('iframe')
|
||||
.first()
|
||||
.iframeLoaded()
|
||||
.its('document')
|
||||
.getInDocument('a')
|
||||
.eq(1)
|
||||
.contains('Activate my account')
|
||||
.invoke('attr', 'href')
|
||||
.then(href => {
|
||||
cy.visit(href);
|
||||
});
|
||||
|
||||
// cy.url().should('include', '/validate/');
|
||||
// cy.contains('Your account is being validated');
|
||||
cy.location().should((loc) => {
|
||||
expect(loc.pathname).to.eq('/');
|
||||
});
|
||||
});
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
// For authoring Nightwatch tests, see
|
||||
// http://nightwatchjs.org/guide#usage
|
||||
|
||||
module.exports = {
|
||||
'default e2e tests': (browser) => {
|
||||
browser
|
||||
.url(process.env.VUE_DEV_SERVER_URL)
|
||||
.waitForElementVisible('#app', 5000)
|
||||
.assert.elementPresent('.hello')
|
||||
.assert.containsText('h1', 'Welcome to Your Vue.js App')
|
||||
.assert.elementCount('img', 1)
|
||||
.end();
|
||||
},
|
||||
};
|
@ -0,0 +1,129 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
let LOCAL_STORAGE_MEMORY = {};
|
||||
|
||||
Cypress.Commands.add("saveLocalStorage", () => {
|
||||
Object.keys(localStorage).forEach(key => {
|
||||
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("restoreLocalStorage", () => {
|
||||
Object.keys(LOCAL_STORAGE_MEMORY).forEach(key => {
|
||||
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkoutSession', async () => {
|
||||
const response = await fetch('/sandbox', {
|
||||
cache: 'no-store',
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
const sessionId = await response.text();
|
||||
return Cypress.env('sessionId', sessionId);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('dropSession', () =>
|
||||
cy.waitForFetches().then(() =>
|
||||
fetch('/sandbox', {
|
||||
method: 'DELETE',
|
||||
headers: { 'x-session-id': Cypress.env('sessionId') },
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
|
||||
const increaseFetches = () => {
|
||||
const count = Cypress.env('fetchCount') || 0;
|
||||
Cypress.env('fetchCount', count + 1);
|
||||
};
|
||||
|
||||
const decreaseFetches = () => {
|
||||
const count = Cypress.env('fetchCount') || 0;
|
||||
Cypress.env('fetchCount', count - 1);
|
||||
};
|
||||
|
||||
const buildTrackableFetchWithSessionId = fetch => (fetchUrl, fetchOptions) => {
|
||||
const { headers } = fetchOptions;
|
||||
const modifiedHeaders = Object.assign(
|
||||
{ 'x-session-id': Cypress.env('sessionId') },
|
||||
headers,
|
||||
);
|
||||
|
||||
const modifiedOptions = Object.assign({}, fetchOptions, {
|
||||
headers: modifiedHeaders,
|
||||
});
|
||||
|
||||
return fetch(fetchUrl, modifiedOptions)
|
||||
.then(result => {
|
||||
decreaseFetches();
|
||||
return Promise.resolve(result);
|
||||
})
|
||||
.catch(result => {
|
||||
decreaseFetches();
|
||||
return Promise.reject(result);
|
||||
});
|
||||
};
|
||||
|
||||
Cypress.on('window:before:load', win => {
|
||||
cy.stub(win, 'fetch', buildTrackableFetchWithSessionId(fetch));
|
||||
});
|
||||
|
||||
Cypress.Commands.add('waitForFetches', () => {
|
||||
if (Cypress.env('fetchCount') <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cy.wait(100).then(() => cy.waitForFetches());
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'iframeLoaded',
|
||||
{ prevSubject: 'element' },
|
||||
($iframe) => {
|
||||
const contentWindow = $iframe.prop('contentWindow')
|
||||
return new Promise(resolve => {
|
||||
if (
|
||||
contentWindow &&
|
||||
contentWindow.document.readyState === 'complete'
|
||||
) {
|
||||
resolve(contentWindow)
|
||||
} else {
|
||||
$iframe.on('load', () => {
|
||||
resolve(contentWindow)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Cypress.Commands.add(
|
||||
'getInDocument',
|
||||
{ prevSubject: 'document' },
|
||||
(document, selector) => Cypress.$(selector, document)
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/index.js 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 commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": "../node_modules",
|
||||
"types": [
|
||||
"cypress"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.*"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue