Commit 69d2188d authored by MrMan's avatar MrMan

Working E2E tests, unit broken b/c of fetch

parent f630b3cb
......@@ -43,6 +43,16 @@ To run the end to end tests for Kindling, run:
`make test-e2e`
#### Running an individual E2E test (with mocha)
Running individual tests inside the suite can be done with mocha:
`mocha --compilers js:babel-register test/e2e/some-page.js`
If you'd like to see debug messages from nightmare, make sure to include `DEBUG=nightmare` like so:
`DEBUG=nightmare mocha --compilers js:babel-register test/e2e/some-page.js`
## Contributing
0. Fork this repo
......
......@@ -13,7 +13,7 @@ System.config({
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*",
"bower:*": "jspm_packages/bower/*",
"vendor/*": "public/vendor/*.js"
"vendor/*": "public/vendor/*"
},
map: {
......
......@@ -6,7 +6,7 @@ import Actions from "../actions";
import FBAuthStore from "./fb-auth";
import LocalStorageBackupMixinGenerator from "../mixins/localstorage-backup";
import { generateURLWithQueryParams } from "../util";
import fetch from "vendor/fetch";
import "vendor/fetch";
import _ from "lodash";
const DEFAULT_STATE = {user: null, fbAccessToken: null};
......@@ -62,7 +62,7 @@ let FBUserStore = Reflux.createStore({
{'access_token': this.state.fbAccessToken});
// When a user logs in, retrieve their information
return fetch.fetch(userInfoURL)
return fetch(userInfoURL)
.then(d => d.json());
},
......
import _ from "lodash";
import fetch from "vendor/fetch";
import Constants from "./constants";
import Actions from "./actions";
import { detectFFOSPlatform } from "./util";
import "vendor/fetch";
let AUTHENTICATION_RETRIES = 0;
......@@ -32,7 +32,7 @@ function fetchFromTinderAPI(url, method="get", bodyJson={}, extraHeaders={}) {
opts = _.extend(opts, {body: JSON.stringify(bodyJson)});
}
return fetch.fetch(url, opts);
return fetch(url, opts);
}
export default {
......
......@@ -41,7 +41,7 @@ export function generateURLWithQueryParams(base, params) {
* @return {Promise} The fetch request promise
*/
export function jsonPOSTRequest(url, json) {
return fetch.fetch(
return fetch(
url,
{
method: "post",
......
......@@ -4,21 +4,14 @@ import Http from 'http';
import NM from 'nightmare';
import "should";
import { every } from "lodash";
import { loginTestUserAndGotoRoot, mockFetch } from "./utils";
import { clearLocalAndSessionStorage, doFakeLoginResponseAtURL, mockFetch } from "./utils";
import E2ETestConstants from "./constants";
// Test constants
let STATIC_SERVER;
let NODE_SERVER;
const DIST_PATH = `${__dirname}/../../dist`;
// Page constants
const NAV_BUTTON_IDS = [
"#recs-page-link-button",
"#matches-page-link-button",
"#preferences-page-link-button",
"body"
];
const TEST_SERVER_PORT = E2ETestConstants.SERVER_PORT + 1; // Hack to ensure that tests don't collide
describe("App main page", function() {
this.timeout(E2ETestConstants.DEFAULT_TIMEOUT);
......@@ -26,7 +19,7 @@ describe("App main page", function() {
before(done => {
// Init nightmare instance (and electron process)
nm = NM();
nm = NM(E2ETestConstants.DEFAULT_NM_CONFIG);
// Create static server
STATIC_SERVER = new Static.Server(DIST_PATH);
......@@ -34,38 +27,40 @@ describe("App main page", function() {
req.addListener('end', () => {
STATIC_SERVER.serve(req, resp);
}).resume();
}).listen(E2ETestConstants.SERVER_PORT, () => {
}).listen(TEST_SERVER_PORT, () => {
// Log in before test starts
Q.all([
nm.loginTestUserAndGotoRoot(),
mockFetch(nm, /https:\/\/api.gotinder.com\/auth/, {data: "some data"}),
]).then(results => {
done();
});
let testServerUrl = E2ETestConstants.BASE_URL_WITH_PORT(TEST_SERVER_PORT);
// Setup test suite
nm.goto(testServerUrl)
.then(clearLocalAndSessionStorage(nm))
.then(doFakeLoginResponseAtURL(nm, testServerUrl))
.then(done);
// mockFetch(nm, /https:\/\/api.gotinder.com\/auth/, {data: "some data"})
});
});
it("The app main page should be up", (done) => {
Q.Promise.resolve(
nm.url()
).then(url => {
url.should.match(/index.html#\/app/);
done();
});
nm.url()
.then(url => {
url.should.match(/index.html#\/app/);
done();
});
});
it("should contain expected navigation links", (done) => {
nm.exists("#recs-page-link-button").then(first => {
nm.exists("#preferences-page-link-buttonz").then(second => {
every([first,second]).should.be.true();
done();
nm.exists("#preferences-page-link-button").then(second => {
nm.exists("#matches-page-link-button").then(third => {
every([first,second, third]).should.be.true();
done();
});
});
});
});
after(done => {
// End the electron process and the node server
Promise.resolve(nm.end()).then(() => {
......
const SERVER_PORT = 8080;
const BASE_URL = `http://localhost:${SERVER_PORT}`;
const BASE_URL = "http://localhost";
const DEFAULT_TIMEOUT = 10000;
// Note, the default phantom config allows for caching,
// so some code changes will not be seen if caching rules are bad on local test http server
const DEFAULT_NM_CONFIG = {
switches: {
'disable-http-cache': true,
'no-proxy-server': true
}
};
function BASE_URL_WITH_PORT(port) {
return `${BASE_URL}:${port}`;
}
export default {
SERVER_PORT,
BASE_URL,
DEFAULT_TIMEOUT
DEFAULT_TIMEOUT,
DEFAULT_NM_CONFIG,
BASE_URL_WITH_PORT
};
......@@ -4,60 +4,81 @@ import Http from 'http';
import NM from 'nightmare';
import "should";
import _ from "lodash";
import E2ETestConstants from "./constants.js";
import { clearLocalAndSessionStorage } from "./utils";
// Test constants
let SERVER_PORT = 8080;
let BASE_URL = `http://localhost:${SERVER_PORT}`;
let STATIC_SERVER;
let NODE_SERVER;
const DEFAULT_TIMEOUT = 10000;
const DIST_PATH = `${__dirname}/../../dist`;
const TEST_SERVER_PORT = E2ETestConstants.SERVER_PORT;
// Page constants
const LOGIN_BUTTON_ID = "#login-button";
describe("Login page", function() {
this.timeout(DEFAULT_TIMEOUT);
this.timeout(E2ETestConstants.DEFAULT_TIMEOUT);
let nm;
before(() => {
before(done => {
// Init nightmare instance (and electron process)
nm = NM(E2ETestConstants.DEFAULT_NM_CONFIG);
// Create static server
STATIC_SERVER = new Static.Server(DIST_PATH);
NODE_SERVER = Http.createServer((req, resp) => {
req.addListener('end', () => {
STATIC_SERVER.serve(req, resp);
}).resume();
}).listen(SERVER_PORT);
});
}).listen(E2ETestConstants.SERVER_PORT, () => {
beforeEach(() => nm = NM());
let testServerUrl = E2ETestConstants.BASE_URL_WITH_PORT(TEST_SERVER_PORT);
// Setup test suite
nm.goto(testServerUrl)
.then(clearLocalAndSessionStorage(nm))
.then(done);
});
});
it("Should have the appropriate title", (done) => {
Promise.resolve(
nm.goto(BASE_URL).title()
).then(title => {
nm.title().then(title => {
title.should.match(/Kindling/);
done();
});
});
it("Should show the login button for a user that isn't logged in", (done) => {
Q.all(
nm.goto(BASE_URL).exists(LOGIN_BUTTON_ID),
nm.goto(BASE_URL).visible(LOGIN_BUTTON_ID)
).then(all => {
all.should.be.true();
done();
it("Should show the login button for a user that isn't logged in", done => {
nm.exists(LOGIN_BUTTON_ID).then(exists => {
nm.screenshot('test.png');
nm.visible(LOGIN_BUTTON_ID).then(visible => {
(exists && visible).should.be.true();
done();
});
});
});
afterEach(done => {
// End the electron process
Promise.resolve(nm.end()).then(done);
after(done => {
// End the electron process and the node server
Promise.resolve(nm.end()).then(() => {
NODE_SERVER.close(done);
});
});
after(() => NODE_SERVER.close());
});
/**
* Returns a promise that when executed, performs some function on a nightmare instance and returns the result.
*
* @param {Object} nm - The nightmare instance on which to perform the function
* @param {Function} fn - The function to perform, which will be given the nightmare instance
*/
function doNMAction(nm, fn) {
return Q.Promise((resolve, reject) => {
fn(nm)
.then(resolve)
.catch(reject);
});
}
......@@ -2,31 +2,86 @@ import Q from 'q';
import NM from 'nightmare';
import E2ETestConstants from './constants';
const TEST_USER_FB_ID = "TESTUSERFBID";
const TEST_USER_TINDER_ID = "TESTUSERFBID";
const TEST_USER_FB_ID_EXPIRES_IN = "9999999";
const TEST_USER_CALLBACK_URL = E2ETestConstants.BASE_URL + `/index.html#/access_token=${TEST_USER_FB_ID}&expires_in=${TEST_USER_FB_ID_EXPIRES_IN}`;
const DEFAULT_TOKEN_INFO = {
accessToken: "TEST_USER_ACCESS_TOKEN",
expiresIn: "9999999"
};
// function setupUserLoginMocks() {
// }
/**
* Generate the URL that would be redirected to as a result of successful/failing auth
*
* @param {string} url - The base URL
* @param {Object} tokenInfo - The information that should have been passed along with the token
* @param {string} tokenInfo.accessToken - The access token
* @param {string} tokenInfo.expiresIn - A stringified number representing when the token expires
*/
function generateMockLoginResponseUrl(url, tokenInfo=DEFAULT_TOKEN_INFO) {
return url + `/index.html#/access_token=${tokenInfo.accessToken}&expires_in=${tokenInfo.expiresIn}`;
}
/**
* Login test user and go to main app page
*/
NM.action('loginTestUserAndGotoRoot', function(done) {
NM.action('fakeLoginResponseAtURL', function(url, done) {
this.goto(generateMockLoginResponseUrl(url));
done();
});
/**
* Clear local and session storage, especially for test setup
*/
NM.action('clearLocalAndSessionStorage', function(done) {
Q.Promise.resolve(
this.goto(TEST_USER_CALLBACK_URL)
this.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
})
).then(done);
});
/**
* Mocka fetch
* Force Nightmare to navigate to a given URL as a result of authentication.
* A URL like "localhost:8080/" would have a fake redirect like "localhost:8080/#/index.html#access_token=..."
*
* @param {Object} nm - the nightmare instance to use
* @param {string} url - the URL that will be used as the base for the fake redirect URL
* @returns A function that when executed, returns a promise that causes NM to navigate
*/
export function doFakeLoginResponseAtURL(nm, url) {
return () => {
return Q.Promise((resolve, reject) => {
nm.goto(generateMockLoginResponseUrl(url));
resolve();
});
};
};
/**
* Clear local and session storage when called
*
* @param {Object} nm - The nightmare instance to use
* @return A Promise that resolves when the storages have been cleared
*/
export function clearLocalAndSessionStorage(nm) {
return () => {
return Q.Promise((resolve, reject) => {
let res = nm.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
resolve();
});
};
};
/**
* Mock a fetch call
*/
export function mockFetch(nm, urlRegex, response) {
return nm.evaluate(function() {
window.originalFetch = window.fetch;
window.fetch = function(url, opts) {
if (url.match(urlRegex) != null) {
return response;
} else {
......@@ -36,4 +91,3 @@ export function mockFetch(nm, urlRegex, response) {
};
});
};
/**
* Modify an async function to disable before/after it runs
*
......@@ -11,7 +10,7 @@ export function TestWithDisabledConsoleLogging(fn) {
// Backup and disable console.log
let OLD_CONSOLE_LOG = console.log;
console.log = undefined;
// Augment done function
let newDone = () => {
console.log = OLD_CONSOLE_LOG;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment