Skip to content

Commit

Permalink
Feat tests (#25)
Browse files Browse the repository at this point in the history
* Adding tests, minor refactor

* test uninstallAddon() needs a better test

* Smoke test for parsePage

* version bump

* moved test constants to mock.js

* prep for merge to dev
  • Loading branch information
khlam authored Oct 30, 2018
1 parent 8ef54ec commit 297470a
Show file tree
Hide file tree
Showing 21 changed files with 358 additions and 139 deletions.
3 changes: 2 additions & 1 deletion docs/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

# Action List:
- [ ] I've bumped `package.json` version (minor or major.)
- [ ] I've kept this branch up-to-date with `dev`.
- [ ] I've kept this branch up-to-date with `dev`.
- [ ] I've added or updated unit tests as appropriate.
1 change: 1 addition & 0 deletions jest.TestFrameworkSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ os.homedir.mockReturnValue(mockHomeDir)
fs.WriteStream.mockImplementation(NOOP)
fs.mkdir.mockImplementation(NOOP)
fs.mkdirSync.mockImplementation(NOOP)
fs.readdirSync.mockImplementation(NOOP)
fs.chmod.mockImplementation(NOOP)
fs.chmodSync.mockImplementation(NOOP)
fs.chown.mockImplementation(NOOP)
Expand Down
2 changes: 1 addition & 1 deletion jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"verbose": true,
"collectCoverage": true,
"globals": {},
"testMatch": [ "**/__tests__/**/*.js?(x)", "**/?(*.)(spec|test).js?(x)" ],
"testMatch": [ "**/__tests__/**/?(*.)(spec|test).js?(x)" ],
"testPathIgnorePatterns": [ "/node_modules/", "/dist/" ],
"setupTestFrameworkScriptFile": "./jest.TestFrameworkSetup.js"
}
13 changes: 7 additions & 6 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Modules to control application life and create native browser window
import { app, BrowserWindow } from 'electron'
import { parseAddonDetails } from './src/parsePage'
import { checkWhichHost } from './src/checkWhichHost/index'
import { checkWhichHost } from './src/checkHost'
import { installAddon } from './src/installAddon'
import { initConfig, readAddonList, saveToAddonList } from './src/config'
import { integrityCheck, checkUpdate } from './src/updater'
import { checkUpdate } from './src/updateAddon'
import { integrityCheck } from './src/integrityCheck'
import { uninstallAddon } from './src/uninstallAddon'
const chokidar = require('chokidar')

Expand Down Expand Up @@ -125,8 +126,8 @@ const { ipcMain } = require('electron')

// newURL listener
ipcMain.on('newURL', (e, newURL) => {
console.log('Received new URL ' + newURL)
console.log('\tSending URL to be matched with host and parse addon page')
console.log('Received new url ' + newURL)
console.log('\tSending url to be matched with host and parse addon page')
const URLObj = checkWhichHost(newURL)
parseAddonDetails(URLObj).then(addonObj => {
mainWindow.webContents.send('modAddonObj', addonObj)
Expand All @@ -148,7 +149,7 @@ ipcMain.on('installAddon', (e, addonObj) => {
// update addon listener, fetches new version number and downloads the addon
ipcMain.on('installUpdate', (e, addonObj) => {
console.log('Received request to update addon ' + addonObj.name)
const URLObj = checkWhichHost(addonObj.URL)
const URLObj = checkWhichHost(addonObj.url)
parseAddonDetails(URLObj).then(addonObj => {
installAddon(addonObj, configObj.addonDir)
.then((newAddon) => {
Expand Down Expand Up @@ -192,7 +193,7 @@ ipcMain.on('uninstallAddon', (e, addonObj) => {
'name': addonObj.name,
'version': addonObj.version,
'host': addonObj.host,
'URL': addonObj.URL,
'url': addonObj.url,
'authors': addonObj.authors,
'status': 'NOT_INSTALLED'
})
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "world-of-addons",
"version": "0.4.1",
"version": "0.4.2",
"description": "Open source addon manager for World of Warcraft. Install, update, and manage all your WoW addons in a single lightweight application.",
"main": "dist/main.bundle.js",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { checkWhichHost } from '../index'
import { checkWhichHost } from '../checkHost'

describe('checkWhichHost function', () => {
describe('GIVEN a valid url', () => {
const addonName = 'dank-memes'
const host = 'curseforge'
const validURL = `https://www.${host}.com/wow/addons/${addonName}`
it('THEN should return a valid URL object', () => {
it('THEN should return a valid url object', () => {
const result = checkWhichHost(validURL)
expect(result.URL).toEqual(validURL)
expect(result.url).toEqual(validURL)
expect(result.name).toEqual(addonName)
expect(result.host).toEqual(host)
})
})
describe('GIVEN a invalid url', () => {
describe('GIVEN an invalid url', () => {
const invalidUrl = `https://www.KevinIsTheBest.com/wow/addons/JetFuel`
it('THEN should return a error object', () => {
const result = checkWhichHost(invalidUrl)
Expand Down
109 changes: 101 additions & 8 deletions src/__tests__/config.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs'
import {initConfig} from '../config'
import { initConfig, readAddonList, saveToAddonList} from '../config'
import { mockConfig, mockInstallAddonsDict } from './mock'
import path from 'path'
import fs from 'fs'

describe('initConfig function', () => {
describe('WHEN checking a config', () => {
Expand All @@ -19,11 +20,6 @@ describe('initConfig function', () => {
})

describe('GIVEN a config exists', () => {
const mockConfig = {
addonDir: mockInstallDir,
addonRecordFile: path.join(mockHomeDir, 'WorldOfAddons','addons.json'),
checkUpdateOnStart: true
}
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockConfig)
Expand All @@ -38,5 +34,102 @@ describe('initConfig function', () => {
})
})
})

})

describe('readAddonList function ', () => {
describe('WHEN reading an addon record file (addons.js) ', () => {
describe('GIVEN a config exists', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockConfig)
})

describe('GIVEN no addon record file exists ', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(false)
})
it('THEN should return an empty dictionary', () => {
let promise = readAddonList(mockConfig)
return promise.then(result => {
expect(result).toEqual({})
})
})
})

describe('GIVEN an addon record file exists and it is not empty', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockInstallAddonsDict)
})
it('THEN should return a full dictionary', () => {
let promise = readAddonList(mockConfig)
return promise.then(result => {
expect(result).toEqual(mockInstallAddonsDict)
})
})
})
})
})
})

describe('saveToAddonList function ', () => {
describe('GIVEN a config exists', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockConfig)
})

describe('GIVEN an addon record file exists and it is empty', () => {
const mockInstallAddonsDict = ""
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockInstallAddonsDict)
})

describe('WHEN saving a new installed Addons dictionary to an addon record file (addons.js) ', () => {
it('THEN should return the new dictionary', () => {
let promise = saveToAddonList(mockConfig, mockInstallAddonsDict)
return promise.then(result => {
expect(result).toEqual(mockInstallAddonsDict)
})
})
})
})

describe('GIVEN an addon record file exists and it is not empty', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockInstallAddonsDict)
})

describe('WHEN saving a new installed Addons dictionary to an addon record file (addons.js) ', () => {
it('THEN should return the new dictionary', () => {
let promise = saveToAddonList(mockConfig, mockInstallAddonsDict)
return promise.then(result => {
expect(result).toEqual(mockInstallAddonsDict)
})
})
})
})
})
describe('GIVEN a config exists', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(true)
mockReadFile(mockConfig)
})
describe('GIVEN an addon record file does not exist', () => {
beforeAll(() => {
fs.existsSync.mockReturnValue(false)
})

describe('WHEN saving a new installed Addons dictionary to an addon record file (addons.js) ', () => {
it('THEN should return the new dictionary', () => {
let promise = saveToAddonList(mockConfig, mockInstallAddonsDict)
return promise.then(result => {
expect(result).toEqual(mockInstallAddonsDict)
})
})
})
})
})
})
57 changes: 57 additions & 0 deletions src/__tests__/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import path from 'path'

export const mockConfig = {
addonDir: mockInstallDir,
addonRecordFile: path.join(mockHomeDir, 'WorldOfAddons','addons.json'),
checkUpdateOnStart: true
}

export const mockAddonObj = {
"URL": "https://www.curseforge.com/wow/addons/a-good-wow-addon",
"authors": [
"you-Are-Now-Breathing-Manually"
],
"displayName": "Wow Addon",
"host": "curseforge",
"name": "a-good-wow-addon",
"status": "INSTALLED",
"version": "1.0.0",
"subdirs": [
"subdir0",
"subdir1",
"subdir2"
]
}

export const mockInstallAddonsDict = {
"a-good-wow-addon": {
"URL": "https://www.curseforge.com/wow/addons/a-good-wow-addon",
"authors": [
"you-Are-Now-Breathing-Manually"
],
"displayName": "Wow Addon0",
"host": "curseforge",
"name": "a-good-wow-addon",
"status": "INSTALLED",
"version": "1.0.0",
"subdirs": [
"subdir1",
"subdir2",
"subdir3"
]
},
"another-wow-addon": {
"URL": "https://www.curseforge.com/wow/addons/another-wow-addon",
"authors": [
"you-Are-Now-Breathing-Manually"
],
"displayName": "Wow Addon1",
"host": "curseforge",
"name": "another-wow-addon",
"status": "INSTALLED",
"version": "999",
"subdirs": [
"subdirOfWow Addon1"
]
}
}
28 changes: 28 additions & 0 deletions src/__tests__/parsePage.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { parseAddonDetails } from '../parsePage'

describe('parseAddonDetails function', () => {
describe('WHEN making a REAL request to curseforge.com', () => {
describe('WHEN using a real URLObj for DBM hosted on Curseforge', () => { // TODO: Sometimes request fails, need to mock websocket and website
it('THEN should return a valid addonObj', () => {
const validURLObj = { 'url': 'https://www.curseforge.com/wow/addons/deadly-boss-mods', 'host': 'curseforge', 'name': 'deadly-boss-mods' }
let promise = parseAddonDetails(validURLObj)
return promise.then(result => {
expect(result.displayName).toEqual('Deadly Boss Mods (DBM)')
expect(result.name).toEqual('deadly-boss-mods')
expect(result.version).not.toBeNull()
expect(result.host).toEqual('curseforge')
expect(result.url).toEqual('https://www.curseforge.com/wow/addons/deadly-boss-mods')
expect(result.authors).toEqual(["mysticalos", "Tandanu", "DBM_Build", "Elnarfim", "Mini_Dragon", "Arta88", "Mave99", "nbluewiz", "oscarucb", "TOM_RUS", "SmoothMcGroove"])
expect(result.status).toEqual('')
})
})
})
describe('WHEN using an invalid test URLObj', () => {
it('THEN should return an error', () => {
const invalidURLObj = { 'url': 'https://www.curseforge.com/wow/addons/test-addon', 'host': 'curseforge', 'name': 'test-addon' }
let promise = parseAddonDetails(invalidURLObj)
expect(promise).rejects.toThrow('Invalid URL.');
})
})
})
})
42 changes: 42 additions & 0 deletions src/__tests__/uninstallAddon.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { mockAddonObj, mockConfig, mockInstallAddonsDict } from './mock'
import { uninstallAddon } from '../uninstallAddon'
import fs from 'fs'

describe('uninstallAddon function', () => {
describe('GIVEN a valid configObj', () => {
describe('GIVEN a valid installAddonsDict', () => {
describe('GIVEN a valid addonObj to be uninstalled', () => {
describe('GIVEN an addon directory exists in the addon install directory', () => {
// Needs to properly test function uninstallAddon(), this
// requires something like simulating a filesystem in memory
beforeEach(() => {
fs.existsSync.mockReturnValue(true)
fs.readdirSync.mockReturnValue(true)
})

it('THEN should delete a-good-wow-addon from the addon dictionary and remove subdir0, subdir1 and subdir2', () => {
let newDict = uninstallAddon(mockAddonObj, mockConfig, mockInstallAddonsDict)
expect(newDict).toEqual({
"another-wow-addon": {
"URL": "https://www.curseforge.com/wow/addons/another-wow-addon",
"authors": [
"you-Are-Now-Breathing-Manually"
],
"displayName": "Wow Addon1",
"host": "curseforge",
"name": "another-wow-addon",
"status": "INSTALLED",
"version": "999",
"subdirs": [
"subdirOfWow Addon1"
]
}
})
})
})

})

})
})
})
18 changes: 18 additions & 0 deletions src/checkHost.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Checks what website hosts the addon
export function checkWhichHost (url) {
if (url.startsWith('https://www.curseforge.com/wow/addons/')) {
return initCurseforgeObj(url)
}

const errorObj = { 'error': `Invalid url '${url}'. Given link does not match parse` }
return errorObj
}

// Creates a JSON object for addons hosted by Curseforge.
// Parses the addon name from the end of the url, this name is how the
// JSON object is referenced by other components
function initCurseforgeObj (url) {
const URLSplit = url.split('https://www.curseforge.com/wow/addons/')
const URLObj = { 'url': url, 'host': 'curseforge', 'name': URLSplit[1] }
return URLObj
}
Loading

0 comments on commit 297470a

Please sign in to comment.