Added unit tests
parent
c88c9720a2
commit
af59febbb5
|
@ -4,7 +4,7 @@
|
||||||
const dotenv = require("dotenv");
|
const dotenv = require("dotenv");
|
||||||
|
|
||||||
// Modules from file
|
// Modules from file
|
||||||
const F95API = require("../app/index.js");
|
const F95API = require("./index.js");
|
||||||
|
|
||||||
// Configure the .env reader
|
// Configure the .env reader
|
||||||
dotenv.config();
|
dotenv.config();
|
|
@ -24,6 +24,7 @@ module.exports.UserData = UserData;
|
||||||
* Shows log messages and other useful functions for module debugging.
|
* Shows log messages and other useful functions for module debugging.
|
||||||
* @param {Boolean} value
|
* @param {Boolean} value
|
||||||
*/
|
*/
|
||||||
|
/* istambul ignore next */
|
||||||
module.exports.debug = function (value) {
|
module.exports.debug = function (value) {
|
||||||
shared.debug = value;
|
shared.debug = value;
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ module.exports.debug = function (value) {
|
||||||
* Indicates whether a user is logged in to the F95Zone platform or not.
|
* Indicates whether a user is logged in to the F95Zone platform or not.
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
|
/* istambul ignore next */
|
||||||
module.exports.isLogged = function () {
|
module.exports.isLogged = function () {
|
||||||
return shared.isLogged;
|
return shared.isLogged;
|
||||||
};
|
};
|
||||||
|
@ -64,7 +66,7 @@ module.exports.login = async function (username, password) {
|
||||||
await creds.fetchToken();
|
await creds.fetchToken();
|
||||||
|
|
||||||
shared.logger.trace(`Authentication for ${username}`);
|
shared.logger.trace(`Authentication for ${username}`);
|
||||||
const result = await networkHelper.autenticate(creds);
|
const result = await networkHelper.authenticate(creds);
|
||||||
shared.isLogged = result.success;
|
shared.isLogged = result.success;
|
||||||
|
|
||||||
if (result.success) shared.logger.info("User logged in through the platform");
|
if (result.success) shared.logger.info("User logged in through the platform");
|
||||||
|
|
|
@ -107,6 +107,7 @@ class GameInfo {
|
||||||
censored: this.censored,
|
censored: this.censored,
|
||||||
engine: this.engine,
|
engine: this.engine,
|
||||||
status: this.status,
|
status: this.status,
|
||||||
|
tags: this.tags,
|
||||||
previewSrc: this.previewSrc,
|
previewSrc: this.previewSrc,
|
||||||
version: this.version,
|
version: this.version,
|
||||||
lastUpdate: this.lastUpdate,
|
lastUpdate: this.lastUpdate,
|
||||||
|
@ -122,9 +123,13 @@ class GameInfo {
|
||||||
* @param {String} json JSON string used to create the new object
|
* @param {String} json JSON string used to create the new object
|
||||||
* @returns {GameInfo}
|
* @returns {GameInfo}
|
||||||
*/
|
*/
|
||||||
/* istanbul ignore next */
|
|
||||||
static fromJSON(json) {
|
static fromJSON(json) {
|
||||||
return Object.assign(new GameInfo(), json);
|
// Convert string
|
||||||
|
const temp = Object.assign(new GameInfo(), JSON.parse(json));
|
||||||
|
|
||||||
|
// JSON cannot transform a string to a date implicitly
|
||||||
|
temp.lastUpdate = new Date(temp.lastUpdate);
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = GameInfo;
|
module.exports = GameInfo;
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
// Public modules from npm
|
// Public modules from npm
|
||||||
const axios = require("axios").default;
|
const axios = require("axios").default;
|
||||||
const { isString } = require("lodash");
|
|
||||||
const ky = require("ky-universal").create({
|
const ky = require("ky-universal").create({
|
||||||
throwHttpErrors: false,
|
throwHttpErrors: false,
|
||||||
});
|
});
|
||||||
|
@ -21,6 +20,7 @@ const userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) " +
|
||||||
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
|
"AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
|
||||||
axiosCookieJarSupport(axios);
|
axiosCookieJarSupport(axios);
|
||||||
const cookieJar = new tough.CookieJar();
|
const cookieJar = new tough.CookieJar();
|
||||||
|
|
||||||
const commonConfig = {
|
const commonConfig = {
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": userAgent,
|
"User-Agent": userAgent,
|
||||||
|
@ -52,9 +52,10 @@ module.exports.fetchHTML = async function (url) {
|
||||||
* and token obtained previously. Save cookies on your
|
* and token obtained previously. Save cookies on your
|
||||||
* device after authentication.
|
* device after authentication.
|
||||||
* @param {Credentials} credentials Platform access credentials
|
* @param {Credentials} credentials Platform access credentials
|
||||||
* @returns {Promise<LoginResul>} Result of the operation
|
* @param {Boolea} force Specifies whether the request should be forced, ignoring any saved cookies
|
||||||
|
* @returns {Promise<LoginResult>} Result of the operation
|
||||||
*/
|
*/
|
||||||
module.exports.autenticate = async function (credentials) {
|
module.exports.authenticate = async function (credentials, force) {
|
||||||
shared.logger.info(`Authenticating with user ${credentials.username}`);
|
shared.logger.info(`Authenticating with user ${credentials.username}`);
|
||||||
if (!credentials.token) throw new Error(`Invalid token for auth: ${credentials.token}`);
|
if (!credentials.token) throw new Error(`Invalid token for auth: ${credentials.token}`);
|
||||||
|
|
||||||
|
@ -75,7 +76,9 @@ module.exports.autenticate = async function (credentials) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Try to log-in
|
// Try to log-in
|
||||||
const response = await axios.post(secureURL, params, commonConfig);
|
let config = Object.assign({}, commonConfig);
|
||||||
|
if (force) delete config.jar;
|
||||||
|
const response = await axios.post(secureURL, params, config);
|
||||||
|
|
||||||
// Parse the response HTML
|
// Parse the response HTML
|
||||||
const $ = cheerio.load(response.data);
|
const $ = cheerio.load(response.data);
|
||||||
|
@ -116,6 +119,7 @@ module.exports.getF95Token = async function() {
|
||||||
* (such as graphics engines and progress statuses)
|
* (such as graphics engines and progress statuses)
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
/* istanbul ignore next */
|
||||||
module.exports.fetchPlatformData = async function() {
|
module.exports.fetchPlatformData = async function() {
|
||||||
// Fetch the response of the platform
|
// Fetch the response of the platform
|
||||||
const response = await exports.fetchGETResponse(f95url.F95_LATEST_UPDATES);
|
const response = await exports.fetchGETResponse(f95url.F95_LATEST_UPDATES);
|
||||||
|
@ -145,6 +149,12 @@ module.exports.fetchPlatformData = async function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
//#region Utility methods
|
//#region Utility methods
|
||||||
|
/**
|
||||||
|
* @protected
|
||||||
|
* Performs a GET request to a specific URL and returns the response.
|
||||||
|
* If the request generates an error (for example 400) `null` is returned.
|
||||||
|
* @param {String} url
|
||||||
|
*/
|
||||||
module.exports.fetchGETResponse = async function(url) {
|
module.exports.fetchGETResponse = async function(url) {
|
||||||
// Secure the URL
|
// Secure the URL
|
||||||
const secureURL = exports.enforceHttpsUrl(url);
|
const secureURL = exports.enforceHttpsUrl(url);
|
||||||
|
@ -162,10 +172,10 @@ module.exports.fetchGETResponse = async function(url) {
|
||||||
* @protected
|
* @protected
|
||||||
* Enforces the scheme of the URL is https and returns the new URL.
|
* Enforces the scheme of the URL is https and returns the new URL.
|
||||||
* @param {String} url
|
* @param {String} url
|
||||||
* @returns {String}
|
* @returns {String} Secure URL or `null` if the argument is not a string
|
||||||
*/
|
*/
|
||||||
module.exports.enforceHttpsUrl = function (url) {
|
module.exports.enforceHttpsUrl = function (url) {
|
||||||
return isString(url) ? url.replace(/^(https?:)?\/\//, "https://") : null;
|
return exports.isStringAValidURL(url) ? url.replace(/^(https?:)?\/\//, "https://") : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,17 +191,17 @@ module.exports.isF95URL = function (url) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
* Checks if the string passed by parameter has a properly formatted and valid path to a URL.
|
* Checks if the string passed by parameter has a
|
||||||
|
* properly formatted and valid path to a URL (HTTP/HTTPS).
|
||||||
* @param {String} url String to check for correctness
|
* @param {String} url String to check for correctness
|
||||||
* @returns {Boolean} true if the string is a valid URL, false otherwise
|
* @returns {Boolean} true if the string is a valid URL, false otherwise
|
||||||
*/
|
*/
|
||||||
module.exports.isStringAValidURL = function (url) {
|
module.exports.isStringAValidURL = function (url) {
|
||||||
try {
|
// Many thanks to Daveo at StackOverflow (https://preview.tinyurl.com/y2f2e2pc)
|
||||||
new URL(url); // skipcq: JS-0078
|
const expression = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||||
return true;
|
const regex = new RegExp(expression);
|
||||||
} catch (err) {
|
if (url.match(regex)) return true;
|
||||||
return false;
|
else return false;
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* istanbul ignore file */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Public modules from npm
|
// Public modules from npm
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "f95api",
|
"name": "f95api",
|
||||||
"version": "1.3.5",
|
"version": "1.5.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"main": "./app/index.js",
|
"main": "./app/index.js",
|
||||||
"name": "f95api",
|
"name": "f95api",
|
||||||
"version": "1.3.5",
|
"version": "1.5.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Millennium Earl"
|
"name": "Millennium Earl"
|
||||||
},
|
},
|
||||||
|
@ -19,7 +19,10 @@
|
||||||
"scraping",
|
"scraping",
|
||||||
"login",
|
"login",
|
||||||
"game",
|
"game",
|
||||||
"games"
|
"games",
|
||||||
|
"data",
|
||||||
|
"userdata",
|
||||||
|
"user data"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"unit-test-mocha": "nyc --reporter=text mocha './test/index-test.js'",
|
"unit-test-mocha": "nyc --reporter=text mocha './test/index-test.js'",
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Core modules
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
// Public modules from npm
|
||||||
|
const _ = require("lodash");
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const sleep = require("sleep");
|
||||||
|
const dotenv = require("dotenv");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const urlHelper = require("../app/scripts/url-helper.js");
|
||||||
|
const F95API = require("../app/index.js");
|
||||||
|
|
||||||
|
// Configure the .env reader
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const COOKIES_SAVE_PATH = "./f95cache/cookies.json";
|
||||||
|
const ENGINES_SAVE_PATH = "./f95cache/engines.json";
|
||||||
|
const STATUSES_SAVE_PATH = "./f95cache/statuses.json";
|
||||||
|
const USERNAME = process.env.F95_USERNAME;
|
||||||
|
const PASSWORD = process.env.F95_PASSWORD;
|
||||||
|
const FAKE_USERNAME = "Fake_Username091276";
|
||||||
|
const FAKE_PASSWORD = "fake_password";
|
||||||
|
|
||||||
|
//F95API.debug(false);
|
||||||
|
|
||||||
|
function randomSleep() {
|
||||||
|
const random = Math.floor(Math.random() * 500) + 50;
|
||||||
|
sleep.msleep(500 + random);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Login without cookies", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
|
||||||
|
before("Set isolation", function () {
|
||||||
|
F95API.setIsolation(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach("Remove all cookies", function () {
|
||||||
|
// Runs before each test in this block
|
||||||
|
if (fs.existsSync(COOKIES_SAVE_PATH)) fs.unlinkSync(COOKIES_SAVE_PATH);
|
||||||
|
if (F95API.isLogged()) F95API.logout();
|
||||||
|
});
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
let testOrder = 0;
|
||||||
|
|
||||||
|
it("Test with valid credentials", async function () {
|
||||||
|
// Gain exclusive use of the cookies
|
||||||
|
while (testOrder !== 0) randomSleep();
|
||||||
|
|
||||||
|
const result = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(result.success).to.be.true;
|
||||||
|
expect(result.message).equal("Authentication successful");
|
||||||
|
|
||||||
|
testOrder = 1;
|
||||||
|
});
|
||||||
|
it("Test with invalid username", async function () {
|
||||||
|
// Gain exclusive use of the cookies
|
||||||
|
while (testOrder !== 1) randomSleep();
|
||||||
|
|
||||||
|
const result = await F95API.login(FAKE_USERNAME, FAKE_PASSWORD);
|
||||||
|
expect(result.success).to.be.false;
|
||||||
|
expect(result.message).to.equal("Incorrect username");
|
||||||
|
|
||||||
|
testOrder = 2;
|
||||||
|
});
|
||||||
|
it("Test with invalid password", async function () {
|
||||||
|
// Gain exclusive use of the cookies
|
||||||
|
while (testOrder !== 2) randomSleep();
|
||||||
|
|
||||||
|
const result = await F95API.login(USERNAME, FAKE_PASSWORD);
|
||||||
|
expect(result.success).to.be.false;
|
||||||
|
expect(result.message).to.equal("Incorrect password");
|
||||||
|
|
||||||
|
testOrder = 3;
|
||||||
|
});
|
||||||
|
it("Test with invalid credentials", async function () {
|
||||||
|
// Gain exclusive use of the cookies
|
||||||
|
while (testOrder !== 3) randomSleep();
|
||||||
|
|
||||||
|
const result = await F95API.login(FAKE_USERNAME, FAKE_PASSWORD);
|
||||||
|
expect(result.success).to.be.false;
|
||||||
|
expect(result.message).to.equal("Incorrect username"); // It should first check the username
|
||||||
|
|
||||||
|
testOrder = 4;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Login with cookies", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
|
||||||
|
before("Log in to create cookies then logout", async function () {
|
||||||
|
// Runs once before the first test in this block
|
||||||
|
if (!fs.existsSync(COOKIES_SAVE_PATH))
|
||||||
|
await F95API.login(USERNAME, PASSWORD); // Download cookies
|
||||||
|
if (F95API.isLogged()) F95API.logout();
|
||||||
|
});
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
it("Test with valid credentials", async function () {
|
||||||
|
const result = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(result.success).to.be.true;
|
||||||
|
expect(result.message).equal("Logged with cookies");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Load base data without cookies", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
|
||||||
|
before("Delete cache if exists", function () {
|
||||||
|
// Runs once before the first test in this block
|
||||||
|
if (fs.existsSync(ENGINES_SAVE_PATH)) fs.unlinkSync(ENGINES_SAVE_PATH);
|
||||||
|
if (fs.existsSync(STATUSES_SAVE_PATH)) fs.unlinkSync(STATUSES_SAVE_PATH);
|
||||||
|
});
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
it("With login", async function () {
|
||||||
|
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(loginResult.success).to.be.true;
|
||||||
|
|
||||||
|
const result = await F95API.loadF95BaseData();
|
||||||
|
|
||||||
|
const enginesCacheExists = fs.existsSync(ENGINES_SAVE_PATH);
|
||||||
|
const statusesCacheExists = fs.existsSync(STATUSES_SAVE_PATH);
|
||||||
|
|
||||||
|
expect(result).to.be.true;
|
||||||
|
expect(enginesCacheExists).to.be.true;
|
||||||
|
expect(statusesCacheExists).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Without login", async function () {
|
||||||
|
if (F95API.isLogged()) F95API.logout();
|
||||||
|
const result = await F95API.loadF95BaseData();
|
||||||
|
expect(result).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Search game data", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(60000); // All tests in this suite get 60 seconds before timeout
|
||||||
|
|
||||||
|
beforeEach("Prepare API", function () {
|
||||||
|
// Runs once before the first test in this block
|
||||||
|
if (F95API.isLogged()) F95API.logout();
|
||||||
|
});
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
let testGame = null;
|
||||||
|
|
||||||
|
it("Search game when logged", async function () {
|
||||||
|
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(loginResult.success).to.be.true;
|
||||||
|
|
||||||
|
const loadResult = await F95API.loadF95BaseData();
|
||||||
|
expect(loadResult).to.be.true;
|
||||||
|
|
||||||
|
// This test depend on the data on F95Zone at
|
||||||
|
// https://f95zone.to/threads/kingdom-of-deception-v0-10-8-hreinn-games.2733/
|
||||||
|
const gamesList = await F95API.getGameData("Kingdom of Deception", false);
|
||||||
|
expect(gamesList.length, "Should find only the game").to.equal(1);
|
||||||
|
const result = gamesList[0];
|
||||||
|
const src = "https://attachments.f95zone.to/2018/09/162821_f9nXfwF.png";
|
||||||
|
|
||||||
|
// Test only the main information
|
||||||
|
expect(result.name).to.equal("Kingdom of Deception");
|
||||||
|
expect(result.author).to.equal("Hreinn Games");
|
||||||
|
expect(result.isMod, "Should be false").to.be.false;
|
||||||
|
expect(result.engine).to.equal("REN'PY");
|
||||||
|
expect(result.previewSource).to.equal(src); // Could be null -> Why sometimes doesn't get the image?
|
||||||
|
testGame = Object.assign({}, result);
|
||||||
|
});
|
||||||
|
it("Search game when not logged", async function () {
|
||||||
|
const result = await F95API.getGameData("Kingdom of Deception", false);
|
||||||
|
expect(result, "Without being logged should return null").to.be.null;
|
||||||
|
});
|
||||||
|
it("Test game serialization", function () {
|
||||||
|
const json = JSON.stringify(testGame);
|
||||||
|
const parsedGameInfo = JSON.parse(json);
|
||||||
|
const result = _.isEqual(parsedGameInfo, testGame);
|
||||||
|
expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Load user data", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
it("Retrieve when logged", async function () {
|
||||||
|
// Login
|
||||||
|
await F95API.login(USERNAME, PASSWORD);
|
||||||
|
|
||||||
|
// Then retrieve user data
|
||||||
|
const data = await F95API.getUserData();
|
||||||
|
|
||||||
|
expect(data).to.exist;
|
||||||
|
expect(data.username).to.equal(USERNAME);
|
||||||
|
});
|
||||||
|
it("Retrieve when not logged", async function () {
|
||||||
|
// Logout
|
||||||
|
if (F95API.isLogged()) F95API.logout();
|
||||||
|
|
||||||
|
// Try to retrieve user data
|
||||||
|
const data = await F95API.getUserData();
|
||||||
|
|
||||||
|
expect(data).to.be.null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Check game update", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
it("Get online game and verify that no update exists", async function () {
|
||||||
|
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(loginResult.success).to.be.true;
|
||||||
|
|
||||||
|
const loadResult = await F95API.loadF95BaseData();
|
||||||
|
expect(loadResult).to.be.true;
|
||||||
|
|
||||||
|
// This test depend on the data on F95Zone at
|
||||||
|
// https://f95zone.to/threads/kingdom-of-deception-v0-10-8-hreinn-games.2733/
|
||||||
|
const result = (await F95API.getGameData("Kingdom of Deception", false))[0];
|
||||||
|
|
||||||
|
const update = await F95API.chekIfGameHasUpdate(result);
|
||||||
|
expect(update).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Verify that update exists from old URL", async function () {
|
||||||
|
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(loginResult.success).to.be.true;
|
||||||
|
|
||||||
|
// This test depend on the data on F95Zone at
|
||||||
|
// https://f95zone.to/threads/perverted-education-v0-9701-april-ryan.1854/
|
||||||
|
const url =
|
||||||
|
"https://f95zone.to/threads/perverted-education-v0-9701-april-ryan.1854/";
|
||||||
|
const result = await F95API.getGameDataFromURL(url);
|
||||||
|
result.version = "0.9600";
|
||||||
|
|
||||||
|
const update = await F95API.chekIfGameHasUpdate(result);
|
||||||
|
expect(update).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test url-helper", function () {
|
||||||
|
//#region Set-up
|
||||||
|
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
||||||
|
//#endregion Set-up
|
||||||
|
|
||||||
|
it("Check if URL exists", async function () {
|
||||||
|
// Check generic URLs...
|
||||||
|
let exists = await urlHelper.urlExists("https://www.google.com/");
|
||||||
|
expect(exists, "Complete valid URL").to.be.true;
|
||||||
|
|
||||||
|
exists = await urlHelper.urlExists("www.google.com");
|
||||||
|
expect(exists, "URl without protocol prefix").to.be.false;
|
||||||
|
|
||||||
|
exists = await urlHelper.urlExists("https://www.google/");
|
||||||
|
expect(exists, "URL without third level domain").to.be.false;
|
||||||
|
|
||||||
|
// Now check for more specific URLs (with redirect)...
|
||||||
|
exists = await urlHelper.urlExists(
|
||||||
|
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/"
|
||||||
|
);
|
||||||
|
expect(exists, "URL with redirect without check").to.be.true;
|
||||||
|
|
||||||
|
exists = await urlHelper.urlExists(
|
||||||
|
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(exists, "URL with redirect with check").to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if URL belong to the platform", async function () {
|
||||||
|
let belong = urlHelper.isF95URL(
|
||||||
|
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/"
|
||||||
|
);
|
||||||
|
expect(belong).to.be.true;
|
||||||
|
|
||||||
|
belong = urlHelper.isF95URL("https://www.google/");
|
||||||
|
expect(belong).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,290 +1,36 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Core modules
|
// Test suite
|
||||||
const fs = require("fs");
|
const api = require("./suites/api-test.js").suite;
|
||||||
|
const credentials = require("./suites/credentials-test.js").suite;
|
||||||
|
const network = require("./suites/network-helper-test.js").suite;
|
||||||
|
const scraper = require("./suites/scraper-test.js").suite;
|
||||||
|
const searcher = require("./suites/searcher-test.js").suite;
|
||||||
|
const uScraper = require("./suites/user-scraper-test.js").suite;
|
||||||
|
|
||||||
// Public modules from npm
|
describe("Test basic function", function testBasic() {
|
||||||
const _ = require("lodash");
|
|
||||||
const expect = require("chai").expect;
|
|
||||||
const sleep = require("sleep");
|
|
||||||
const dotenv = require("dotenv");
|
|
||||||
|
|
||||||
// Modules from file
|
|
||||||
const urlHelper = require("../app/scripts/url-helper.js");
|
|
||||||
const F95API = require("../app/index.js");
|
|
||||||
|
|
||||||
// Configure the .env reader
|
|
||||||
dotenv.config();
|
|
||||||
|
|
||||||
const COOKIES_SAVE_PATH = "./f95cache/cookies.json";
|
|
||||||
const ENGINES_SAVE_PATH = "./f95cache/engines.json";
|
|
||||||
const STATUSES_SAVE_PATH = "./f95cache/statuses.json";
|
|
||||||
const USERNAME = process.env.F95_USERNAME;
|
|
||||||
const PASSWORD = process.env.F95_PASSWORD;
|
|
||||||
const FAKE_USERNAME = "FakeUsername091276";
|
|
||||||
const FAKE_PASSWORD = "fake_password";
|
|
||||||
|
|
||||||
//F95API.debug(false);
|
|
||||||
|
|
||||||
function randomSleep() {
|
|
||||||
const random = Math.floor(Math.random() * 500) + 50;
|
|
||||||
sleep.msleep(500 + random);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Login without cookies", function () {
|
|
||||||
//#region Set-up
|
//#region Set-up
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
this.timeout(15000); // All tests in this suite get 15 seconds before timeout
|
||||||
|
|
||||||
before("Set isolation", function () {
|
|
||||||
F95API.setIsolation(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach("Remove all cookies", function () {
|
|
||||||
// Runs before each test in this block
|
|
||||||
if (fs.existsSync(COOKIES_SAVE_PATH)) fs.unlinkSync(COOKIES_SAVE_PATH);
|
|
||||||
if (F95API.isLogged()) F95API.logout();
|
|
||||||
});
|
|
||||||
//#endregion Set-up
|
//#endregion Set-up
|
||||||
|
|
||||||
let testOrder = 0;
|
describe("Test credentials class", credentials.bind(this));
|
||||||
|
describe("Test network helper", network.bind(this));
|
||||||
it("Test with valid credentials", async function () {
|
|
||||||
// Gain exclusive use of the cookies
|
|
||||||
while (testOrder !== 0) randomSleep();
|
|
||||||
|
|
||||||
const result = await F95API.login(USERNAME, PASSWORD);
|
|
||||||
expect(result.success).to.be.true;
|
|
||||||
expect(result.message).equal("Authentication successful");
|
|
||||||
|
|
||||||
testOrder = 1;
|
|
||||||
});
|
|
||||||
it("Test with invalid username", async function () {
|
|
||||||
// Gain exclusive use of the cookies
|
|
||||||
while (testOrder !== 1) randomSleep();
|
|
||||||
|
|
||||||
const result = await F95API.login(FAKE_USERNAME, FAKE_PASSWORD);
|
|
||||||
expect(result.success).to.be.false;
|
|
||||||
expect(result.message).to.equal("Incorrect username");
|
|
||||||
|
|
||||||
testOrder = 2;
|
|
||||||
});
|
|
||||||
it("Test with invalid password", async function () {
|
|
||||||
// Gain exclusive use of the cookies
|
|
||||||
while (testOrder !== 2) randomSleep();
|
|
||||||
|
|
||||||
const result = await F95API.login(USERNAME, FAKE_PASSWORD);
|
|
||||||
expect(result.success).to.be.false;
|
|
||||||
expect(result.message).to.equal("Incorrect password");
|
|
||||||
|
|
||||||
testOrder = 3;
|
|
||||||
});
|
|
||||||
it("Test with invalid credentials", async function () {
|
|
||||||
// Gain exclusive use of the cookies
|
|
||||||
while (testOrder !== 3) randomSleep();
|
|
||||||
|
|
||||||
const result = await F95API.login(FAKE_USERNAME, FAKE_PASSWORD);
|
|
||||||
expect(result.success).to.be.false;
|
|
||||||
expect(result.message).to.equal("Incorrect username"); // It should first check the username
|
|
||||||
|
|
||||||
testOrder = 4;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Login with cookies", function () {
|
describe("Test F95 modules", function testF95Modules() {
|
||||||
//#region Set-up
|
//#region Set-up
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
this.timeout(15000); // All tests in this suite get 15 seconds before timeout
|
||||||
|
|
||||||
before("Log in to create cookies then logout", async function () {
|
|
||||||
// Runs once before the first test in this block
|
|
||||||
if (!fs.existsSync(COOKIES_SAVE_PATH))
|
|
||||||
await F95API.login(USERNAME, PASSWORD); // Download cookies
|
|
||||||
if (F95API.isLogged()) F95API.logout();
|
|
||||||
});
|
|
||||||
//#endregion Set-up
|
//#endregion Set-up
|
||||||
|
|
||||||
it("Test with valid credentials", async function () {
|
describe("Test scraper methods", scraper.bind(this));
|
||||||
const result = await F95API.login(USERNAME, PASSWORD);
|
describe("Test searcher methods", searcher.bind(this));
|
||||||
expect(result.success).to.be.true;
|
describe("Test user scraper methods", uScraper.bind(this));
|
||||||
expect(result.message).equal("Logged with cookies");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Load base data without cookies", function () {
|
describe("Test complete API", function testAPI() {
|
||||||
//#region Set-up
|
//#region Set-up
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
this.timeout(15000); // All tests in this suite get 15 seconds before timeout
|
||||||
|
|
||||||
before("Delete cache if exists", function () {
|
|
||||||
// Runs once before the first test in this block
|
|
||||||
if (fs.existsSync(ENGINES_SAVE_PATH)) fs.unlinkSync(ENGINES_SAVE_PATH);
|
|
||||||
if (fs.existsSync(STATUSES_SAVE_PATH)) fs.unlinkSync(STATUSES_SAVE_PATH);
|
|
||||||
});
|
|
||||||
//#endregion Set-up
|
//#endregion Set-up
|
||||||
|
|
||||||
it("With login", async function () {
|
describe("Test API", api.bind(this));
|
||||||
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
|
||||||
expect(loginResult.success).to.be.true;
|
|
||||||
|
|
||||||
const result = await F95API.loadF95BaseData();
|
|
||||||
|
|
||||||
const enginesCacheExists = fs.existsSync(ENGINES_SAVE_PATH);
|
|
||||||
const statusesCacheExists = fs.existsSync(STATUSES_SAVE_PATH);
|
|
||||||
|
|
||||||
expect(result).to.be.true;
|
|
||||||
expect(enginesCacheExists).to.be.true;
|
|
||||||
expect(statusesCacheExists).to.be.true;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Without login", async function () {
|
|
||||||
if (F95API.isLogged()) F95API.logout();
|
|
||||||
const result = await F95API.loadF95BaseData();
|
|
||||||
expect(result).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Search game data", function () {
|
|
||||||
//#region Set-up
|
|
||||||
this.timeout(60000); // All tests in this suite get 60 seconds before timeout
|
|
||||||
|
|
||||||
beforeEach("Prepare API", function () {
|
|
||||||
// Runs once before the first test in this block
|
|
||||||
if (F95API.isLogged()) F95API.logout();
|
|
||||||
});
|
|
||||||
//#endregion Set-up
|
|
||||||
|
|
||||||
let testGame = null;
|
|
||||||
|
|
||||||
it("Search game when logged", async function () {
|
|
||||||
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
|
||||||
expect(loginResult.success).to.be.true;
|
|
||||||
|
|
||||||
const loadResult = await F95API.loadF95BaseData();
|
|
||||||
expect(loadResult).to.be.true;
|
|
||||||
|
|
||||||
// This test depend on the data on F95Zone at
|
|
||||||
// https://f95zone.to/threads/kingdom-of-deception-v0-10-8-hreinn-games.2733/
|
|
||||||
const gamesList = await F95API.getGameData("Kingdom of Deception", false);
|
|
||||||
expect(gamesList.length, "Should find only the game").to.equal(1);
|
|
||||||
const result = gamesList[0];
|
|
||||||
const src = "https://attachments.f95zone.to/2018/09/162821_f9nXfwF.png";
|
|
||||||
|
|
||||||
// Test only the main information
|
|
||||||
expect(result.name).to.equal("Kingdom of Deception");
|
|
||||||
expect(result.author).to.equal("Hreinn Games");
|
|
||||||
expect(result.isMod, "Should be false").to.be.false;
|
|
||||||
expect(result.engine).to.equal("REN'PY");
|
|
||||||
expect(result.previewSource).to.equal(src); // Could be null -> Why sometimes doesn't get the image?
|
|
||||||
testGame = Object.assign({}, result);
|
|
||||||
});
|
|
||||||
it("Search game when not logged", async function () {
|
|
||||||
const result = await F95API.getGameData("Kingdom of Deception", false);
|
|
||||||
expect(result, "Without being logged should return null").to.be.null;
|
|
||||||
});
|
|
||||||
it("Test game serialization", function () {
|
|
||||||
const json = JSON.stringify(testGame);
|
|
||||||
const parsedGameInfo = JSON.parse(json);
|
|
||||||
const result = _.isEqual(parsedGameInfo, testGame);
|
|
||||||
expect(result).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Load user data", function () {
|
|
||||||
//#region Set-up
|
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
|
||||||
//#endregion Set-up
|
|
||||||
|
|
||||||
it("Retrieve when logged", async function () {
|
|
||||||
// Login
|
|
||||||
await F95API.login(USERNAME, PASSWORD);
|
|
||||||
|
|
||||||
// Then retrieve user data
|
|
||||||
const data = await F95API.getUserData();
|
|
||||||
|
|
||||||
expect(data).to.exist;
|
|
||||||
expect(data.username).to.equal(USERNAME);
|
|
||||||
});
|
|
||||||
it("Retrieve when not logged", async function () {
|
|
||||||
// Logout
|
|
||||||
if (F95API.isLogged()) F95API.logout();
|
|
||||||
|
|
||||||
// Try to retrieve user data
|
|
||||||
const data = await F95API.getUserData();
|
|
||||||
|
|
||||||
expect(data).to.be.null;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Check game update", function () {
|
|
||||||
//#region Set-up
|
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
|
||||||
//#endregion Set-up
|
|
||||||
|
|
||||||
it("Get online game and verify that no update exists", async function () {
|
|
||||||
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
|
||||||
expect(loginResult.success).to.be.true;
|
|
||||||
|
|
||||||
const loadResult = await F95API.loadF95BaseData();
|
|
||||||
expect(loadResult).to.be.true;
|
|
||||||
|
|
||||||
// This test depend on the data on F95Zone at
|
|
||||||
// https://f95zone.to/threads/kingdom-of-deception-v0-10-8-hreinn-games.2733/
|
|
||||||
const result = (await F95API.getGameData("Kingdom of Deception", false))[0];
|
|
||||||
|
|
||||||
const update = await F95API.chekIfGameHasUpdate(result);
|
|
||||||
expect(update).to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Verify that update exists from old URL", async function () {
|
|
||||||
const loginResult = await F95API.login(USERNAME, PASSWORD);
|
|
||||||
expect(loginResult.success).to.be.true;
|
|
||||||
|
|
||||||
// This test depend on the data on F95Zone at
|
|
||||||
// https://f95zone.to/threads/perverted-education-v0-9701-april-ryan.1854/
|
|
||||||
const url =
|
|
||||||
"https://f95zone.to/threads/perverted-education-v0-9701-april-ryan.1854/";
|
|
||||||
const result = await F95API.getGameDataFromURL(url);
|
|
||||||
result.version = "0.9600";
|
|
||||||
|
|
||||||
const update = await F95API.chekIfGameHasUpdate(result);
|
|
||||||
expect(update).to.be.true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("Test url-helper", function () {
|
|
||||||
//#region Set-up
|
|
||||||
this.timeout(30000); // All tests in this suite get 30 seconds before timeout
|
|
||||||
//#endregion Set-up
|
|
||||||
|
|
||||||
it("Check if URL exists", async function () {
|
|
||||||
// Check generic URLs...
|
|
||||||
let exists = await urlHelper.urlExists("https://www.google.com/");
|
|
||||||
expect(exists, "Complete valid URL").to.be.true;
|
|
||||||
|
|
||||||
exists = await urlHelper.urlExists("www.google.com");
|
|
||||||
expect(exists, "URl without protocol prefix").to.be.false;
|
|
||||||
|
|
||||||
exists = await urlHelper.urlExists("https://www.google/");
|
|
||||||
expect(exists, "URL without third level domain").to.be.false;
|
|
||||||
|
|
||||||
// Now check for more specific URLs (with redirect)...
|
|
||||||
exists = await urlHelper.urlExists(
|
|
||||||
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/"
|
|
||||||
);
|
|
||||||
expect(exists, "URL with redirect without check").to.be.true;
|
|
||||||
|
|
||||||
exists = await urlHelper.urlExists(
|
|
||||||
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/",
|
|
||||||
true
|
|
||||||
);
|
|
||||||
expect(exists, "URL with redirect with check").to.be.false;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Check if URL belong to the platform", async function () {
|
|
||||||
let belong = urlHelper.isF95URL(
|
|
||||||
"https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/"
|
|
||||||
);
|
|
||||||
expect(belong).to.be.true;
|
|
||||||
|
|
||||||
belong = urlHelper.isF95URL("https://www.google/");
|
|
||||||
expect(belong).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
});
|
|
@ -0,0 +1,64 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const dotenv = require("dotenv");
|
||||||
|
const {
|
||||||
|
isEqual
|
||||||
|
} = require("lodash");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const F95API = require("../../app/index.js");
|
||||||
|
|
||||||
|
// Configure the .env reader
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const USERNAME = process.env.F95_USERNAME;
|
||||||
|
const PASSWORD = process.env.F95_PASSWORD;
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
// Global suite variables
|
||||||
|
const gameURL = "https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/";
|
||||||
|
|
||||||
|
it("Test login", async function testLogin() {
|
||||||
|
const result = await F95API.login(USERNAME, PASSWORD);
|
||||||
|
expect(result.success).to.be.true;
|
||||||
|
expect(F95API.isLogged()).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test user data fetching", async function testUserDataFetch() {
|
||||||
|
const userdata = await F95API.getUserData();
|
||||||
|
expect(userdata.username).to.be.equal(USERNAME);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test game update checking", async function testGameUpdateCheck() {
|
||||||
|
// We force the creation of a GameInfo object,
|
||||||
|
// knowing that the checkIfGameHasUpdate() function
|
||||||
|
// only needs the game URL
|
||||||
|
const info = new F95API.GameInfo();
|
||||||
|
|
||||||
|
// The gameURL identifies a game for which we know there is an update
|
||||||
|
info.url = gameURL;
|
||||||
|
|
||||||
|
// Check for updates
|
||||||
|
const update = await F95API.checkIfGameHasUpdate(info);
|
||||||
|
expect(update).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test game data fetching", async function testGameDataFetch() {
|
||||||
|
// Search a game by name
|
||||||
|
const gameList = await F95API.getGameData("perverted education", false);
|
||||||
|
|
||||||
|
// We know that there is only one game with the selected name
|
||||||
|
expect(gameList.length).to.be.equal(1, `There should be only one game, not ${gameList.length}`);
|
||||||
|
const game = gameList[0];
|
||||||
|
|
||||||
|
// Than we fetch a game from URL
|
||||||
|
const gameFromURL = await F95API.getGameDataFromURL(game.url);
|
||||||
|
|
||||||
|
// The two games must be equal
|
||||||
|
const equal = isEqual(game, gameFromURL);
|
||||||
|
expect(equal).to.be.true;
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,52 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const Credentials = require("../../app/scripts/classes/credentials.js");
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
it("Check token formatting", async function testValidToken() {
|
||||||
|
// Token example:
|
||||||
|
// 1604309951,0338213c00fcbd894fd9415e6ba08403
|
||||||
|
// 1604309986,ebdb75502337699381f0f55c86353555
|
||||||
|
// 1604310008,2d50d55808e5ec3a157ec01953da9d26
|
||||||
|
|
||||||
|
// Fetch token (is a GET request, we don't need the credentials)
|
||||||
|
const cred = new Credentials(null, null);
|
||||||
|
await cred.fetchToken();
|
||||||
|
|
||||||
|
// Parse token for assert
|
||||||
|
const splitted = cred.token.split(",");
|
||||||
|
const unique = splitted[0];
|
||||||
|
const hash = splitted[1];
|
||||||
|
expect(splitted.length).to.be.equal(2, "The token consists of two parts");
|
||||||
|
|
||||||
|
// Check type of parts
|
||||||
|
expect(isNumeric(unique)).to.be.true;
|
||||||
|
expect(isNumeric(hash)).to.be.false;
|
||||||
|
|
||||||
|
// The second part is most probably the MD5 hash of something
|
||||||
|
expect(hash.length).to.be.equal(32, "Hash should have 32 hex chars");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//#region Private methods
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* Check if a string is a number
|
||||||
|
* @param {String} str
|
||||||
|
* @author Dan, Ben Aston
|
||||||
|
* @see https://preview.tinyurl.com/y46jqwkt
|
||||||
|
*/
|
||||||
|
function isNumeric(str) {
|
||||||
|
// We only process strings!
|
||||||
|
if (typeof str != "string") return false;
|
||||||
|
|
||||||
|
// Use type coercion to parse the _entirety_ of the string
|
||||||
|
// (`parseFloat` alone does not do this) and ensure strings
|
||||||
|
// of whitespace fail
|
||||||
|
return !isNaN(str) && !isNaN(parseFloat(str));
|
||||||
|
}
|
||||||
|
//#endregion
|
|
@ -0,0 +1,107 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const dotenv = require("dotenv");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const Credentials = require("../../app/scripts/classes/credentials.js");
|
||||||
|
const networkHelper = require("../../app/scripts/network-helper.js");
|
||||||
|
const {
|
||||||
|
F95_SEARCH_URL
|
||||||
|
} = require("../../app/scripts/constants/url.js");
|
||||||
|
|
||||||
|
// Configure the .env reader
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const USERNAME = process.env.F95_USERNAME;
|
||||||
|
const PASSWORD = process.env.F95_PASSWORD;
|
||||||
|
const FAKE_USERNAME = "Fake_Username091276";
|
||||||
|
const FAKE_PASSWORD = "fake_password";
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
// Global suite variables
|
||||||
|
const gameURL = "https://f95zone.to/threads/perverted-education-v0-9601-april-ryan.1854/";
|
||||||
|
|
||||||
|
it("Check if URL exists", async function checkURLExistence() {
|
||||||
|
// Check generic URLs...
|
||||||
|
let exists = await networkHelper.urlExists("https://www.google.com/");
|
||||||
|
expect(exists, "Complete valid URL").to.be.true;
|
||||||
|
|
||||||
|
exists = await networkHelper.urlExists("www.google.com");
|
||||||
|
expect(exists, "URl without protocol prefix").to.be.false;
|
||||||
|
|
||||||
|
exists = await networkHelper.urlExists("https://www.google/");
|
||||||
|
expect(exists, "URL without third level domain").to.be.false;
|
||||||
|
|
||||||
|
// Now check for more specific URLs (with redirect)...
|
||||||
|
exists = await networkHelper.urlExists(gameURL);
|
||||||
|
expect(exists, "URL with redirect without check").to.be.true;
|
||||||
|
|
||||||
|
exists = await networkHelper.urlExists(gameURL, true);
|
||||||
|
expect(exists, "URL with redirect with check").to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check if URL belong to the platform", function checkIfURLIsF95() {
|
||||||
|
let belong = networkHelper.isF95URL(gameURL);
|
||||||
|
expect(belong).to.be.true;
|
||||||
|
|
||||||
|
belong = networkHelper.isF95URL("https://www.google/");
|
||||||
|
expect(belong).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Enforce secure URLs", function testSecureURLEnforcement() {
|
||||||
|
// This URL is already secure, should remain the same
|
||||||
|
let enforced = networkHelper.enforceHttpsUrl(gameURL);
|
||||||
|
expect(enforced).to.be.equal(gameURL, "The game URL is already secure");
|
||||||
|
|
||||||
|
// This URL is not secure
|
||||||
|
enforced = networkHelper.enforceHttpsUrl("http://www.google.com");
|
||||||
|
expect(enforced).to.be.equal("https://www.google.com", "The URL was without SSL/TLS (HTTPs)");
|
||||||
|
|
||||||
|
// Finally, we check when we pass a invalid URL
|
||||||
|
enforced = networkHelper.enforceHttpsUrl("http://invalidurl");
|
||||||
|
expect(enforced).to.be.null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check URL redirect", async function checkURLRedirect() {
|
||||||
|
// gameURL is an old URL it has been verified that it generates a redirect
|
||||||
|
const redirectURL = await networkHelper.getUrlRedirect(gameURL);
|
||||||
|
expect(redirectURL).to.not.be.equal(gameURL, "The original URL has redirect");
|
||||||
|
|
||||||
|
// If we recheck the new URL, we find that no redirect happens
|
||||||
|
const secondRedirectURL = await networkHelper.getUrlRedirect(redirectURL);
|
||||||
|
expect(secondRedirectURL).to.be.equal(redirectURL, "The URL has no redirect");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Check response to GET request", async function testGETResponse() {
|
||||||
|
// We should be able to fetch a game page
|
||||||
|
let response = await networkHelper.fetchGETResponse(gameURL);
|
||||||
|
expect(response.status).to.be.equal(200, "The operation must be successful");
|
||||||
|
|
||||||
|
// We should NOT be able to fetch the search page (we must be logged)
|
||||||
|
response = await networkHelper.fetchGETResponse(F95_SEARCH_URL);
|
||||||
|
expect(response).to.be.null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test for authentication to platform", async function testAuthentication() {
|
||||||
|
// Try to authenticate with valid credentials
|
||||||
|
const creds = new Credentials(USERNAME, PASSWORD);
|
||||||
|
await creds.fetchToken();
|
||||||
|
const validResult = await networkHelper.authenticate(creds);
|
||||||
|
expect(validResult.success).to.be.true;
|
||||||
|
|
||||||
|
// Now we use fake credentials
|
||||||
|
const fakeCreds = new Credentials(FAKE_USERNAME, FAKE_PASSWORD);
|
||||||
|
await fakeCreds.fetchToken();
|
||||||
|
const invalidResult = await networkHelper.authenticate(fakeCreds, true);
|
||||||
|
expect(invalidResult.success).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test fetching HTML", async function testFetchHTML() {
|
||||||
|
// This should return the HTML code of the page
|
||||||
|
const html = await networkHelper.fetchHTML(gameURL);
|
||||||
|
expect(html.startsWith("<!DOCTYPE html>")).to.be.true;
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const { isEqual } = require("lodash");
|
||||||
|
const GameInfo = require("../../app/scripts/classes/game-info.js");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const scraper = require("../../app/scripts/scraper.js");
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
// Global suite variables
|
||||||
|
const gameURL = "https://f95zone.to/threads/kingdom-of-deception-v0-10-8-hreinn-games.2733/";
|
||||||
|
const previewSrc = "https://attachments.f95zone.to/2018/09/162821_f9nXfwF.png";
|
||||||
|
|
||||||
|
it("Search game", async function () {
|
||||||
|
// This test depend on the data on F95Zone at gameURL
|
||||||
|
const result = await scraper.getGameInfo(gameURL);
|
||||||
|
|
||||||
|
// Test only the main information
|
||||||
|
expect(result.name).to.equal("Kingdom of Deception");
|
||||||
|
expect(result.author).to.equal("Hreinn Games");
|
||||||
|
expect(result.isMod, "Should be false").to.be.false;
|
||||||
|
expect(result.engine).to.equal("Ren'Py");
|
||||||
|
expect(result.previewSrc).to.equal(previewSrc, "Preview not equals");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Test game serialization", async function testGameSerialization() {
|
||||||
|
// This test depend on the data on F95Zone at gameURL
|
||||||
|
const testGame = await scraper.getGameInfo(gameURL);
|
||||||
|
|
||||||
|
// Serialize...
|
||||||
|
const json = JSON.stringify(testGame);
|
||||||
|
|
||||||
|
// Deserialize...
|
||||||
|
const parsedGameInfo = GameInfo.fromJSON(json);
|
||||||
|
|
||||||
|
// Compare with lodash
|
||||||
|
const result = isEqual(parsedGameInfo, testGame);
|
||||||
|
expect(result).to.be.true;
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,64 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const dotenv = require("dotenv");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const Credentials = require("../../app/scripts/classes/credentials.js");
|
||||||
|
const searcher = require("../../app/scripts/searcher.js");
|
||||||
|
const {
|
||||||
|
authenticate
|
||||||
|
} = require("../../app/scripts/network-helper.js");
|
||||||
|
|
||||||
|
// Configure the .env reader
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const USERNAME = process.env.F95_USERNAME;
|
||||||
|
const PASSWORD = process.env.F95_PASSWORD;
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
// TODO:
|
||||||
|
// This method should delete the store F95Zone cookies,
|
||||||
|
// but what if the other tests require them?
|
||||||
|
|
||||||
|
// it("Search game when not logged", async function searchGameWhenNotLogged() {
|
||||||
|
// // Search for a game that we know has only one result
|
||||||
|
// // but without logging in first
|
||||||
|
// const urls = await searcher.searchGame("kingdom of deception");
|
||||||
|
// expect(urls.lenght).to.be.equal(0, "There should not be any URL");
|
||||||
|
// });
|
||||||
|
|
||||||
|
it("Search game", async function searchGame() {
|
||||||
|
// Authenticate
|
||||||
|
const result = await auth();
|
||||||
|
expect(result.success, "Authentication should be successful").to.be.true;
|
||||||
|
|
||||||
|
// Search for a game that we know has only one result
|
||||||
|
const urls = await searcher.searchGame("kingdom of deception");
|
||||||
|
expect(urls.length).to.be.equal(1, `There should be only one game result instead of ${urls.length}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Search mod", async function searchMod() {
|
||||||
|
// Authenticate
|
||||||
|
const result = await auth();
|
||||||
|
expect(result.success, "Authentication should be successful").to.be.true;
|
||||||
|
|
||||||
|
// Search for a mod that we know has only one result
|
||||||
|
const urls = await searcher.searchMod("kingdom of deception jdmod");
|
||||||
|
expect(urls.length).to.be.equal(1, `There should be only one mod result instead of ${urls.length}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//#region Private methods
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* Simple wrapper for authentication.
|
||||||
|
*/
|
||||||
|
async function auth() {
|
||||||
|
const creds = new Credentials(USERNAME, PASSWORD);
|
||||||
|
await creds.fetchToken();
|
||||||
|
return await authenticate(creds);
|
||||||
|
}
|
||||||
|
//#endregion Private methods
|
|
@ -0,0 +1,54 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Public module from npm
|
||||||
|
const expect = require("chai").expect;
|
||||||
|
const dotenv = require("dotenv");
|
||||||
|
|
||||||
|
// Modules from file
|
||||||
|
const Credentials = require("../../app/scripts/classes/credentials.js");
|
||||||
|
const uScraper = require("../../app/scripts/user-scraper.js");
|
||||||
|
const {
|
||||||
|
authenticate
|
||||||
|
} = require("../../app/scripts/network-helper.js");
|
||||||
|
|
||||||
|
// Configure the .env reader
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
const USERNAME = process.env.F95_USERNAME;
|
||||||
|
const PASSWORD = process.env.F95_PASSWORD;
|
||||||
|
|
||||||
|
module.exports.suite = function suite() {
|
||||||
|
// TODO:
|
||||||
|
// This method should delete the store F95Zone cookies,
|
||||||
|
// but what if the other tests require them?
|
||||||
|
|
||||||
|
// it("Fetch data when not logged", async function fetchUserDataWhenLogged() {
|
||||||
|
// const data = await uScraper.getUserData();
|
||||||
|
// expect(data.username).to.be.equal("");
|
||||||
|
// expect(data.avatarSrc).to.be.equal("");
|
||||||
|
// expect(data.watchedThreads.length).to.be.equal(0);
|
||||||
|
// });
|
||||||
|
|
||||||
|
it("Fetch data when logged", async function fetchUserDataWhenNotLogged() {
|
||||||
|
// Authenticate
|
||||||
|
const result = await auth();
|
||||||
|
expect(result.success, "Authentication should be successful").to.be.true;
|
||||||
|
|
||||||
|
// We test only for the username, the other test data depends on the user logged
|
||||||
|
const data = await uScraper.getUserData();
|
||||||
|
expect(data.username).to.be.equal(USERNAME);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
//#region Private methods
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* Simple wrapper for authentication.
|
||||||
|
*/
|
||||||
|
async function auth() {
|
||||||
|
const creds = new Credentials(USERNAME, PASSWORD);
|
||||||
|
await creds.fetchToken();
|
||||||
|
return await authenticate(creds);
|
||||||
|
}
|
||||||
|
//#endregion Private methods
|
Loading…
Reference in New Issue